mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-07-02 19:21:36 +02:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56c606e1c4 | |||
| cbc28c235c | |||
| dd1aa5139e | |||
| 89b3149732 | |||
| d2b794ec5a | |||
| 921a3ebc63 | |||
| 428657a97e | |||
| fe9745235a | |||
| 1264df4a72 | |||
| 5b5d68be86 | |||
| e92041783c | |||
| 6912d52faf | |||
| 3685fccfaf | |||
| 36b0a93a6c | |||
| fed1c87663 | |||
| e2e83abeb5 | |||
| 3aef0ad7a2 | |||
| e68a73c3d5 | |||
| bd83a630ff | |||
| 52ac7e37dc | |||
| 0eccf43a8e | |||
| fa423370b1 |
@@ -0,0 +1,5 @@
|
|||||||
|
# Copilot Instructions
|
||||||
|
|
||||||
|
## Project Guidelines
|
||||||
|
- When running tests in this workspace, do not run tests for the net48 target framework.
|
||||||
|
- When changing System.Text.Json code in this workspace, verify API availability for netstandard2.0 and netstandard2.1 instead of assuming newer APIs exist.
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
name: Publish to NuGet
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
name: Build, Pack, and Publish
|
||||||
|
runs-on: windows-2022
|
||||||
|
permissions:
|
||||||
|
id-token: write # enable GitHub OIDC token issuance for this job
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build projects
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Get-ChildItem ./src -Recurse -Filter *.csproj |
|
||||||
|
ForEach-Object {
|
||||||
|
dotnet build $_.FullName -c Release
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Pack projects
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Get-ChildItem ./src -Recurse -Filter *.csproj |
|
||||||
|
ForEach-Object {
|
||||||
|
dotnet pack $_.FullName -c Release --no-build -o ./packages
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: NuGet login (OIDC → temp API key)
|
||||||
|
uses: NuGet/login@v1
|
||||||
|
id: login
|
||||||
|
with:
|
||||||
|
user: ${{ secrets.NUGET_USER }}
|
||||||
|
|
||||||
|
- name: Push to NuGet
|
||||||
|
run: dotnet nuget push "**/packages/*.nupkg" --api-key ${{steps.login.outputs.NUGET_API_KEY}} --source "https://api.nuget.org/v3/index.json" --skip-duplicate
|
||||||
+30
-2
@@ -1,16 +1,44 @@
|
|||||||
|
# 2.11.0 (12 June 2026)
|
||||||
|
- [#1475](https://github.com/wiremock/WireMock.Net/pull/1475) - Update NuGet packages (Aspire, MessagePack and more) [security] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1476](https://github.com/wiremock/WireMock.Net/pull/1476) - Fix BodyParser [bug] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1473](https://github.com/wiremock/WireMock.Net/issues/1473) - JsonPartialWildCardMatcher With DateTime Regex Stopped Matching (Regression?) [bug]
|
||||||
|
|
||||||
|
# 2.10.0 (07 June 2026)
|
||||||
|
- [#1472](https://github.com/wiremock/WireMock.Net/pull/1472) - Update JsonConverter to 0.13.0 [bug] contributed by [StefH](https://github.com/StefH)
|
||||||
|
|
||||||
|
# 2.9.0 (02 June 2026)
|
||||||
|
- [#1470](https://github.com/wiremock/WireMock.Net/pull/1470) - Fix WireMock.Net.Aspire project when using Aspire 13.4.0 [bug] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1469](https://github.com/wiremock/WireMock.Net/issues/1469) - WireMock.Net doesn't play well with Aspire 13.4.0 [bug]
|
||||||
|
|
||||||
|
# 2.8.0 (31 May 2026)
|
||||||
|
- [#1447](https://github.com/wiremock/WireMock.Net/pull/1447) - Add SystemTextJsonMatchers [feature] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1466](https://github.com/wiremock/WireMock.Net/pull/1466) - Bump System.Text.RegularExpressions from 4.3.0 to 4.3.1 in Aspire Example project [dependencies, .NET] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
||||||
|
- [#1467](https://github.com/wiremock/WireMock.Net/pull/1467) - Bump System.Net.Http from 4.3.0 to 4.3.4 in Aspire Example project [dependencies, .NET] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
||||||
|
- [#1468](https://github.com/wiremock/WireMock.Net/pull/1468) - Update JsonMatcher to support IgnoreArrayOrder [feature] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1439](https://github.com/wiremock/WireMock.Net/issues/1439) - JSON reference properties cannot be used when using System.Text.Json serialization [bug]
|
||||||
|
- [#1445](https://github.com/wiremock/WireMock.Net/issues/1445) - Configurable JSON DE-serialization support (Newtonsoft.Json vs System.Text.Json) [feature]
|
||||||
|
- [#1460](https://github.com/wiremock/WireMock.Net/issues/1460) - Option to ignore array order when comparing json body [feature]
|
||||||
|
|
||||||
|
# 2.7.0 (24 May 2026)
|
||||||
|
- [#1457](https://github.com/wiremock/WireMock.Net/pull/1457) - Update OpenTelemetry.Api from 1.14.0 to 1.15.3 in unit test project [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
||||||
|
- [#1459](https://github.com/wiremock/WireMock.Net/pull/1459) - chore: update Handlebars 2.5.2 to 2.5.5 [dependencies] contributed by [kamisoft-fr](https://github.com/kamisoft-fr)
|
||||||
|
- [#1461](https://github.com/wiremock/WireMock.Net/pull/1461) - Update Testcontainers nuget package to 4.12.0 [dependencies] contributed by [MD-V](https://github.com/MD-V)
|
||||||
|
- [#1462](https://github.com/wiremock/WireMock.Net/pull/1462) - Update Scriban.Signed to latest [dependencies] contributed by [StefH](https://github.com/StefH)
|
||||||
|
- [#1458](https://github.com/wiremock/WireMock.Net/issues/1458) - update Handlebars Humanizer package version [feature]
|
||||||
|
|
||||||
# 2.6.0 (11 May 2026)
|
# 2.6.0 (11 May 2026)
|
||||||
- [#1455](https://github.com/wiremock/WireMock.Net/pull/1455) - Fix request storing when RequestLogExpirationDuration is set [bug] [bug] contributed by [pbenko-xitaso](https://github.com/pbenko-xitaso)
|
- [#1455](https://github.com/wiremock/WireMock.Net/pull/1455) - Fix request storing when RequestLogExpirationDuration is set [bug] [bug] contributed by [pbenko-xitaso](https://github.com/pbenko-xitaso)
|
||||||
- [#1454](https://github.com/wiremock/WireMock.Net/issues/1454) - No requests stored in Standalone when RequestLogExpirationDuration is set [bug]
|
- [#1454](https://github.com/wiremock/WireMock.Net/issues/1454) - No requests stored in Standalone when RequestLogExpirationDuration is set [bug]
|
||||||
|
|
||||||
# 2.5.0 (04 May 2026)
|
# 2.5.0 (04 May 2026)
|
||||||
- [#1451](https://github.com/wiremock/WireMock.Net/pull/1451) - Feature/early mismatch [feature] contributed by [Stepami](https://github.com/Stepami)
|
- [#1451](https://github.com/wiremock/WireMock.Net/pull/1451) - Feature/early mismatch [feature] contributed by [Stepami](https://github.com/Stepami)
|
||||||
- [#1452](https://github.com/wiremock/WireMock.Net/pull/1452) - Bump log4net from 2.0.15 to 3.3.0 in example console app [dependencies, .NET] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
- [#1452](https://github.com/wiremock/WireMock.Net/pull/1452) - Bump log4net from 2.0.15 to 3.3.0 in example console app [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
||||||
- [#1453](https://github.com/wiremock/WireMock.Net/pull/1453) - Fix CVE-2026-40021: upgrade log4net to 3.3.0 in examples/WireMock.Net.Service/packages.config [dependencies] contributed by [Copilot](https://github.com/apps/copilot-swe-agent)
|
- [#1453](https://github.com/wiremock/WireMock.Net/pull/1453) - Fix CVE-2026-40021: upgrade log4net to 3.3.0 in examples/WireMock.Net.Service/packages.config [dependencies] contributed by [Copilot](https://github.com/apps/copilot-swe-agent)
|
||||||
- [#1442](https://github.com/wiremock/WireMock.Net/issues/1442) - Bug: [grpc] WithBodyAsProtoBuf exception on match [bug]
|
- [#1442](https://github.com/wiremock/WireMock.Net/issues/1442) - Bug: [grpc] WithBodyAsProtoBuf exception on match [bug]
|
||||||
|
|
||||||
# 2.4.0 (24 April 2026)
|
# 2.4.0 (24 April 2026)
|
||||||
- [#1437](https://github.com/wiremock/WireMock.Net/pull/1437) - Added feature to enable and disable mappings [feature] contributed by [jayaraman-venkatesan](https://github.com/jayaraman-venkatesan)
|
- [#1437](https://github.com/wiremock/WireMock.Net/pull/1437) - Added feature to enable and disable mappings [feature] contributed by [jayaraman-venkatesan](https://github.com/jayaraman-venkatesan)
|
||||||
- [#1450](https://github.com/wiremock/WireMock.Net/pull/1450) - Bump OpenTelemetry.Exporter.OpenTelemetryProtocol from 1.14.0 to 1.15.x [dependencies, .NET] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
- [#1450](https://github.com/wiremock/WireMock.Net/pull/1450) - Bump OpenTelemetry.Exporter.OpenTelemetryProtocol from 1.14.0 to 1.15.x [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
||||||
- [#1421](https://github.com/wiremock/WireMock.Net/issues/1421) - Deactivate mapping without deleting it [feature]
|
- [#1421](https://github.com/wiremock/WireMock.Net/issues/1421) - Deactivate mapping without deleting it [feature]
|
||||||
|
|
||||||
# 2.3.0 (20 April 2026)
|
# 2.3.0 (20 April 2026)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VersionPrefix>2.6.0</VersionPrefix>
|
<VersionPrefix>2.11.0</VersionPrefix>
|
||||||
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
|
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
|
||||||
<PackageProjectUrl>https://github.com/wiremock/WireMock.Net</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/wiremock/WireMock.Net</PackageProjectUrl>
|
||||||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2025.2.4" PrivateAssets="All" />
|
<PackageReference Include="JetBrains.Annotations" Version="2025.2.4" PrivateAssets="All" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.103" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.300" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
rem https://github.com/StefH/GitHubReleaseNotes
|
rem https://github.com/StefH/GitHubReleaseNotes
|
||||||
|
|
||||||
SET version=2.6.0
|
SET version=2.11.0
|
||||||
|
|
||||||
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels wontfix test question invalid doc duplicate example environment --version %version% --token %GH_TOKEN%
|
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels wontfix test question invalid doc duplicate example environment --version %version% --token %GH_TOKEN%
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# 2.6.0 (11 May 2026)
|
# 2.11.0 (12 June 2026)
|
||||||
- #1455 Fix request storing when RequestLogExpirationDuration is set [bug] [bug]
|
- #1475 Update NuGet packages (Aspire, MessagePack and more) [security]
|
||||||
- #1454 No requests stored in Standalone when RequestLogExpirationDuration is set [bug]
|
- #1476 Fix BodyParser [bug]
|
||||||
|
- #1473 JsonPartialWildCardMatcher With DateTime Regex Stopped Matching (Regression?) [bug]
|
||||||
|
|
||||||
The full release notes can be found here: https://github.com/wiremock/WireMock.Net/blob/master/CHANGELOG.md
|
The full release notes can be found here: https://github.com/wiremock/WireMock.Net/blob/master/CHANGELOG.md
|
||||||
@@ -39,8 +39,9 @@ A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) w
|
|||||||
| | |
|
| | |
|
||||||
| ***Quality*** | |
|
| ***Quality*** | |
|
||||||
| **Build Azure** | [](https://stef.visualstudio.com/WireMock.Net/_build/latest?definitionId=61) |
|
| **Build Azure** | [](https://stef.visualstudio.com/WireMock.Net/_build/latest?definitionId=61) |
|
||||||
|
| **Build GitHub** | [](https://github.com/wiremock/WireMock.Net/actions/workflows/ci.yml)
|
||||||
| **Quality** | [](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net) [](https://www.codefactor.io/repository/github/wiremock/wiremock.net) |
|
| **Quality** | [](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net) [](https://www.codefactor.io/repository/github/wiremock/wiremock.net) |
|
||||||
| **Sonar Bugs** | [](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net&resolved=false&types=BUG) [](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net&resolved=false&types=CODE_SMELL) |
|
| **SonarQube** | [](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net&resolved=false&types=BUG) [](https://sonarcloud.io/project/issues?id=WireMock-Net_WireMock.Net&resolved=false&types=CODE_SMELL) |
|
||||||
| **Coverage** | [](https://sonarcloud.io/component_measures?id=WireMock-Net_WireMock.Net&metric=coverage) [](https://codecov.io/gh/wiremock/WireMock.Net)|
|
| **Coverage** | [](https://sonarcloud.io/component_measures?id=WireMock-Net_WireMock.Net&metric=coverage) [](https://codecov.io/gh/wiremock/WireMock.Net)|
|
||||||
| **TIOBE** | [TIOBE Quality Indicator](https://ticsdemo.tiobe.com/tiobeweb/DEMO/TqiDashboard.html#axes=Project(WireMock.Net),Sub()&metric=tqi)
|
| **TIOBE** | [TIOBE Quality Indicator](https://ticsdemo.tiobe.com/tiobeweb/DEMO/TqiDashboard.html#axes=Project(WireMock.Net),Sub()&metric=tqi)
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) w
|
|||||||
| | | |
|
| | | |
|
||||||
| **WireMock.Net.Extensions.Routing** | [](https://www.nuget.org/packages/WireMock.Net.Extensions.Routing) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Extensions.Routing)
|
| **WireMock.Net.Extensions.Routing** | [](https://www.nuget.org/packages/WireMock.Net.Extensions.Routing) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Extensions.Routing)
|
||||||
| **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.Matchers.SystemTextJsonPath** | [](https://www.nuget.org/packages/WireMock.Net.Matchers.SystemTextJsonPath) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.SystemTextJsonPath)
|
||||||
| **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.MimePart** | [](https://www.nuget.org/packages/WireMock.Net.MimePart) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.MimePart)
|
||||||
| **WireMock.Net.GraphQL** | [](https://www.nuget.org/packages/WireMock.Net.GraphQL) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.GraphQL)
|
| **WireMock.Net.GraphQL** | [](https://www.nuget.org/packages/WireMock.Net.GraphQL) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.GraphQL)
|
||||||
@@ -76,7 +78,7 @@ A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) w
|
|||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
🔺 **WireMock.Net.Minimal** does not include *WireMock.Net.MimePart*, *WireMock.Net.GraphQL*, *WireMock.Net.ProtoBuf* and *WireMock.Net.OpenTelemetry*.
|
🔺 **WireMock.Net.Minimal** does not include *WireMock.Net.MimePart*, *WireMock.Net.GraphQL*, *WireMock.Net.ProtoBuf*, *WireMock.Net.OpenTelemetry* and *WireMock.Net.Matchers.SystemTextJsonPath*.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+30
-33
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 18
|
# Visual Studio Version 18
|
||||||
VisualStudioVersion = 18.0.11205.157
|
VisualStudioVersion = 18.0.11205.157
|
||||||
@@ -38,8 +37,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Client", "examples\WireMock.Net.Client\WireMock.Net.Client.csproj", "{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Client", "examples\WireMock.Net.Client\WireMock.Net.Client.csproj", "{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Service", "examples\Wiremock.Net.Service\WireMock.Net.Service.csproj", "{7F0B2446-0363-4720-AF46-F47F83B557DC}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.RequestLogTest", "examples\WireMock.Net.Console.RequestLogTest\WireMock.Net.Console.RequestLogTest.csproj", "{A9D039B9-7509-4CF1-9EFD-87EB82998575}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.RequestLogTest", "examples\WireMock.Net.Console.RequestLogTest\WireMock.Net.Console.RequestLogTest.csproj", "{A9D039B9-7509-4CF1-9EFD-87EB82998575}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.OpenApiParser.ConsoleApp", "examples\WireMock.Net.OpenApiParser.ConsoleApp\WireMock.Net.OpenApiParser.ConsoleApp.csproj", "{5C09FB93-1535-4F92-AF26-21E8A061EE4A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.OpenApiParser.ConsoleApp", "examples\WireMock.Net.OpenApiParser.ConsoleApp\WireMock.Net.OpenApiParser.ConsoleApp.csproj", "{5C09FB93-1535-4F92-AF26-21E8A061EE4A}"
|
||||||
@@ -76,10 +73,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Testcontainers
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TestcontainersExample", "examples\WireMock.Net.TestcontainersExample\WireMock.Net.TestcontainersExample.csproj", "{56A38798-C48B-4A4A-B805-071E05C02CE1}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.TestcontainersExample", "examples\WireMock.Net.TestcontainersExample\WireMock.Net.TestcontainersExample.csproj", "{56A38798-C48B-4A4A-B805-071E05C02CE1}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0147029F-FA4A-44B3-B79A-3C3574054EE4}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultipartUploader", "tools\MultipartUploader\MultipartUploader.csproj", "{07C30227-ADEC-4BDE-8CDC-849D85A690BB}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.NET8", "examples\WireMock.Net.Console.NET8\WireMock.Net.Console.NET8.csproj", "{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Console.NET8", "examples\WireMock.Net.Console.NET8\WireMock.Net.Console.NET8.csproj", "{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueProxy", "examples\WireMockAzureQueueProxy\WireMockAzureQueueProxy.csproj", "{7FC0B409-2682-40EE-B3B9-3930D6769D01}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueProxy", "examples\WireMockAzureQueueProxy\WireMockAzureQueueProxy.csproj", "{7FC0B409-2682-40EE-B3B9-3930D6769D01}"
|
||||||
@@ -156,6 +149,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.TestWebApplica
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.RestClient.AwesomeAssertions", "src\WireMock.Net.RestClient.AwesomeAssertions\WireMock.Net.RestClient.AwesomeAssertions.csproj", "{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.RestClient.AwesomeAssertions", "src\WireMock.Net.RestClient.AwesomeAssertions\WireMock.Net.RestClient.AwesomeAssertions.csproj", "{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Matchers.SystemTextJsonPath", "src\WireMock.Net.Matchers.SystemTextJsonPath\WireMock.Net.Matchers.SystemTextJsonPath.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Service", "examples\WireMock.Net.Service\WireMock.Net.Service.csproj", "{7F0B2446-0363-4720-AF46-F47F83B557DC}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -238,18 +235,6 @@ Global
|
|||||||
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}.Release|x64.Build.0 = Release|Any CPU
|
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}.Release|x86.ActiveCfg = Release|Any CPU
|
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}.Release|x86.Build.0 = Release|Any CPU
|
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{A9D039B9-7509-4CF1-9EFD-87EB82998575}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
@@ -394,18 +379,6 @@ Global
|
|||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|x64.Build.0 = Release|Any CPU
|
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|x86.ActiveCfg = Release|Any CPU
|
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|x86.Build.0 = Release|Any CPU
|
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
@@ -850,6 +823,30 @@ Global
|
|||||||
{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A}.Release|x64.Build.0 = Release|Any CPU
|
{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A}.Release|x86.ActiveCfg = Release|Any CPU
|
{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A}.Release|x86.Build.0 = Release|Any CPU
|
{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -861,7 +858,6 @@ Global
|
|||||||
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
{B6269AAC-170A-43D5-8B9A-579DED3D9A95} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
{31DC2EF8-C3FE-467D-84BE-FB5D956E612E} = {0BB8B634-407A-4610-A91F-11586990767A}
|
{31DC2EF8-C3FE-467D-84BE-FB5D956E612E} = {0BB8B634-407A-4610-A91F-11586990767A}
|
||||||
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{74D91AD0-D96D-4FD2-AEC5-CC49D38346C0} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{7F0B2446-0363-4720-AF46-F47F83B557DC} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
|
||||||
{A9D039B9-7509-4CF1-9EFD-87EB82998575} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{A9D039B9-7509-4CF1-9EFD-87EB82998575} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{5C09FB93-1535-4F92-AF26-21E8A061EE4A} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{5C09FB93-1535-4F92-AF26-21E8A061EE4A} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{B6269AAC-170A-4346-8B9A-579DED3D9A95} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
{B6269AAC-170A-4346-8B9A-579DED3D9A95} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
@@ -876,7 +872,6 @@ Global
|
|||||||
{BAA9EC2A-874B-45CE-8E51-A73622DC7F3D} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{BAA9EC2A-874B-45CE-8E51-A73622DC7F3D} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{56A38798-C48B-4A4A-B805-071E05C02CE1} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{07C30227-ADEC-4BDE-8CDC-849D85A690BB} = {0147029F-FA4A-44B3-B79A-3C3574054EE4}
|
|
||||||
{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{1EA72C0F-92E9-486B-8FFE-53F992BFC4AA} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{7FC0B409-2682-40EE-B3B9-3930D6769D01} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{7FC0B409-2682-40EE-B3B9-3930D6769D01} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{B1580A38-84E7-44BE-8FE7-3EE5031D74A1} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{B1580A38-84E7-44BE-8FE7-3EE5031D74A1} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
@@ -914,6 +909,8 @@ Global
|
|||||||
{2CE8E3A6-59CC-FE9C-9399-AD54E1FA862B} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{2CE8E3A6-59CC-FE9C-9399-AD54E1FA862B} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{3B05CC76-C3CB-8667-6B65-3129DFB25681} = {0BB8B634-407A-4610-A91F-11586990767A}
|
{3B05CC76-C3CB-8667-6B65-3129DFB25681} = {0BB8B634-407A-4610-A91F-11586990767A}
|
||||||
{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
{F4B2B967-98D7-4D93-9A5C-5EF7B84B941A} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
|
{7F0B2446-0363-4720-AF46-F47F83B557DC} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Sdk Name="Aspire.AppHost.Sdk" Version="13.1.0" />
|
<Sdk Name="Aspire.AppHost.Sdk" Version="13.4.0" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
@@ -18,7 +18,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting.AppHost" Version="13.1.0" />
|
<PackageReference Include="Aspire.Hosting.AppHost" Version="13.4.3" />
|
||||||
|
|
||||||
|
<!-- CVE-2026-48109 -->
|
||||||
|
<PackageReference Include="MessagePack" Version="2.5.302" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Sdk Name="Aspire.AppHost.Sdk" Version="13.1.0" />
|
<Sdk Name="Aspire.AppHost.Sdk" Version="13.4.0" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
@@ -15,7 +15,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting.AppHost" Version="13.1.0" />
|
<PackageReference Include="Aspire.Hosting.AppHost" Version="13.4.3" />
|
||||||
|
|
||||||
|
<!-- CVE-2026-48109 -->
|
||||||
|
<PackageReference Include="MessagePack" Version="2.5.302" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
<PackageReference Include="Aspire.Hosting.Testing" Version="13.1.0" />
|
<PackageReference Include="Aspire.Hosting.Testing" Version="13.1.0" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
|
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||||
|
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||||
<PackageReference Include="xunit" Version="2.5.3" />
|
<PackageReference Include="xunit" Version="2.5.3" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.25.1" />
|
<PackageReference Include="Google.Protobuf" Version="3.33.5" />
|
||||||
<PackageReference Include="Grpc.Net.Client" Version="2.60.0" />
|
<PackageReference Include="Grpc.Net.Client" Version="2.76.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.60.0">
|
<PackageReference Include="Grpc.Tools" Version="2.78.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>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using log4net;
|
using log4net;
|
||||||
using log4net.Config;
|
using log4net.Config;
|
||||||
using log4net.Repository;
|
using log4net.Repository;
|
||||||
@@ -12,7 +10,7 @@ namespace WireMock.Net.Console.NET8;
|
|||||||
|
|
||||||
static class Program
|
static class Program
|
||||||
{
|
{
|
||||||
private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
|
private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()!);
|
||||||
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
|
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
|
||||||
|
|
||||||
static async Task Main(params string[] args)
|
static async Task Main(params string[] args)
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="WireMock.Net" Version="1.25.0" />
|
<PackageReference Include="WireMock.Net" Version="2.10.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -32,6 +32,9 @@
|
|||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<StartupObject>Wiremock.Net.Service.Program</StartupObject>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
@@ -94,7 +97,7 @@
|
|||||||
<Version>2.3.9</Version>
|
<Version>2.3.9</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="WireMock.Net">
|
<PackageReference Include="WireMock.Net">
|
||||||
<Version>1.25.0</Version>
|
<Version>2.10.0</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
|||||||
@@ -246,8 +246,8 @@ internal class Program
|
|||||||
throw new InvalidOperationException($"The {nameof(TestcontainersSettings.OS.DockerEndpointAuthConfig)} is null. Check if Docker is started.");
|
throw new InvalidOperationException($"The {nameof(TestcontainersSettings.OS.DockerEndpointAuthConfig)} is null. Check if Docker is started.");
|
||||||
}
|
}
|
||||||
|
|
||||||
using var dockerClientConfig = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration();
|
var dockerClientBuilder = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientBuilder();
|
||||||
using var dockerClient = dockerClientConfig.CreateClient();
|
using var dockerClient = dockerClientBuilder.Build();
|
||||||
|
|
||||||
var version = await dockerClient.System.GetVersionAsync();
|
var version = await dockerClient.System.GetVersionAsync();
|
||||||
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
|
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class WireMockService : IWireMockService
|
|||||||
|
|
||||||
_server = WireMockServer.Start(_settings);
|
_server = WireMockServer.Start(_settings);
|
||||||
|
|
||||||
_logger.LogInformation($"WireMock.Net server settings {JsonConvert.SerializeObject(_settings)}");
|
_logger.LogInformation("WireMock.Net server settings {Settings}", JsonConvert.SerializeObject(_settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
</ItemGroup>-->
|
</ItemGroup>-->
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentBuilder" Version="0.14.0">
|
<PackageReference Include="FluentBuilder" Version="0.15.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>
|
||||||
|
|||||||
@@ -45,7 +45,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting" Version="13.1.0" />
|
<PackageReference Include="Aspire.Hosting" Version="13.4.3" />
|
||||||
|
|
||||||
|
<!-- CVE-2026-48109 -->
|
||||||
|
<PackageReference Include="MessagePack" Version="2.5.302" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -21,11 +21,6 @@ public class WireMockHealthCheck(WireMockServerResource resource) : IHealthCheck
|
|||||||
return HealthCheckResult.Unhealthy("WireMock.Net is not healthy");
|
return HealthCheckResult.Unhealthy("WireMock.Net is not healthy");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.ApiMappingState == WireMockMappingState.NotSubmitted)
|
|
||||||
{
|
|
||||||
return HealthCheckResult.Unhealthy("WireMock.Net has not received mappings");
|
|
||||||
}
|
|
||||||
|
|
||||||
return HealthCheckResult.Healthy();
|
return HealthCheckResult.Healthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,4 +36,4 @@ public class WireMockHealthCheck(WireMockServerResource resource) : IHealthCheck
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,13 @@ internal class WireMockLifecycleSubscriber(ILoggerFactory loggerFactory) : IDist
|
|||||||
|
|
||||||
var endpoint = wireMockServerResource.GetEndpoint();
|
var endpoint = wireMockServerResource.GetEndpoint();
|
||||||
Debug.Assert(endpoint.IsAllocated);
|
Debug.Assert(endpoint.IsAllocated);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
eventing.Subscribe<ResourceReadyEvent>(async (@event, ct) =>
|
||||||
|
{
|
||||||
|
if (@event.Resource is WireMockServerResource wireMockServerResource)
|
||||||
|
{
|
||||||
await wireMockServerResource.WaitForHealthAsync(ct);
|
await wireMockServerResource.WaitForHealthAsync(ct);
|
||||||
|
|
||||||
await wireMockServerResource.CallAddProtoDefinitionsAsync(ct);
|
await wireMockServerResource.CallAddProtoDefinitionsAsync(ct);
|
||||||
|
|||||||
@@ -31,19 +31,19 @@ public partial class WireMockAssertions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CustomAssertion]
|
[CustomAssertion]
|
||||||
public AndConstraint<WireMockAssertions> WithBodyAsJson(object body, string because = "", params object[] becauseArgs)
|
public AndConstraint<WireMockAssertions> WithBodyAsJson(object body, IJsonMatcher? jsonMatcher = null, string because = "", params object[] becauseArgs)
|
||||||
{
|
{
|
||||||
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
|
return WithBodyAsJson(jsonMatcher ?? new JsonMatcher(body), because, becauseArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomAssertion]
|
[CustomAssertion]
|
||||||
public AndConstraint<WireMockAssertions> WithBodyAsJson(string body, string because = "", params object[] becauseArgs)
|
public AndConstraint<WireMockAssertions> WithBodyAsJson(string body, IJsonMatcher? jsonMatcher = null, string because = "", params object[] becauseArgs)
|
||||||
{
|
{
|
||||||
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
|
return WithBodyAsJson(jsonMatcher ?? new JsonMatcher(body), because, becauseArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomAssertion]
|
[CustomAssertion]
|
||||||
public AndConstraint<WireMockAssertions> WithBodyAsJson(IObjectMatcher matcher, string because = "", params object[] becauseArgs)
|
public AndConstraint<WireMockAssertions> WithBodyAsJson(IJsonMatcher matcher, string because = "", params object[] becauseArgs)
|
||||||
{
|
{
|
||||||
var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsJson, matcher);
|
var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsJson, matcher);
|
||||||
|
|
||||||
@@ -126,15 +126,44 @@ public partial class WireMockAssertions
|
|||||||
|
|
||||||
private static string? FormatBody(object? body)
|
private static string? FormatBody(object? body)
|
||||||
{
|
{
|
||||||
return body switch
|
if (body == null)
|
||||||
{
|
{
|
||||||
null => null,
|
return null;
|
||||||
string str => str,
|
}
|
||||||
AnyOf<string, StringPattern>[] stringPatterns => FormatBodies(stringPatterns.Select(p => p.GetPattern())),
|
|
||||||
byte[] bytes => $"byte[{bytes.Length}] {{...}}",
|
if (body is string str)
|
||||||
JToken jToken => jToken.ToString(Formatting.None),
|
{
|
||||||
_ => JToken.FromObject(body).ToString(Formatting.None)
|
return str;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (body is AnyOf<string, StringPattern>[] stringPatterns)
|
||||||
|
{
|
||||||
|
return FormatBodies(stringPatterns.Select(p => p.GetPattern()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body is byte[] bytes)
|
||||||
|
{
|
||||||
|
return $"byte[{bytes.Length}] {{...}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body is JToken jToken)
|
||||||
|
{
|
||||||
|
return jToken.ToString(Formatting.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.IO.FileNotFoundException : Could not load file or assembly 'System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
|
||||||
|
var typeName = body.GetType().FullName;
|
||||||
|
if (typeName == "System.Text.Json.JsonElement")
|
||||||
|
{
|
||||||
|
return ((dynamic)body).GetRawText();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName == "System.Text.Json.JsonDocument")
|
||||||
|
{
|
||||||
|
return ((dynamic)body).RootElement.GetRawText();
|
||||||
|
}
|
||||||
|
|
||||||
|
return JToken.FromObject(body).ToString(Formatting.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? FormatBodies(IEnumerable<object?> bodies)
|
private static string? FormatBodies(IEnumerable<object?> bodies)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>WireMock.Net.Routing extends WireMock.Net with modern, minimal-API-style routing for .NET</Description>
|
<Description>WireMock.Net.Routing extends WireMock.Net with modern, minimal-API-style routing for .NET</Description>
|
||||||
<Authors>Gennadii Saltyshchak</Authors>
|
<Authors>Gennadii Saltyshchak</Authors>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JsonConverter.Abstractions" Version="0.9.0" />
|
<PackageReference Include="JsonConverter.Abstractions" Version="0.13.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -31,19 +31,19 @@ public partial class WireMockAssertions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CustomAssertion]
|
[CustomAssertion]
|
||||||
public AndConstraint<WireMockAssertions> WithBodyAsJson(object body, string because = "", params object[] becauseArgs)
|
public AndConstraint<WireMockAssertions> WithBodyAsJson(object body, IJsonMatcher? jsonMatcher = null, string because = "", params object[] becauseArgs)
|
||||||
{
|
{
|
||||||
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
|
return WithBodyAsJson(jsonMatcher ?? new JsonMatcher(body), because, becauseArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomAssertion]
|
[CustomAssertion]
|
||||||
public AndConstraint<WireMockAssertions> WithBodyAsJson(string body, string because = "", params object[] becauseArgs)
|
public AndConstraint<WireMockAssertions> WithBodyAsJson(string body, IJsonMatcher? jsonMatcher = null, string because = "", params object[] becauseArgs)
|
||||||
{
|
{
|
||||||
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
|
return WithBodyAsJson(jsonMatcher ?? new JsonMatcher(body), because, becauseArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomAssertion]
|
[CustomAssertion]
|
||||||
public AndConstraint<WireMockAssertions> WithBodyAsJson(IObjectMatcher matcher, string because = "", params object[] becauseArgs)
|
public AndConstraint<WireMockAssertions> WithBodyAsJson(IJsonMatcher matcher, string because = "", params object[] becauseArgs)
|
||||||
{
|
{
|
||||||
var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsJson, matcher);
|
var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsJson, matcher);
|
||||||
|
|
||||||
@@ -126,15 +126,44 @@ public partial class WireMockAssertions
|
|||||||
|
|
||||||
private static string? FormatBody(object? body)
|
private static string? FormatBody(object? body)
|
||||||
{
|
{
|
||||||
return body switch
|
if (body == null)
|
||||||
{
|
{
|
||||||
null => null,
|
return null;
|
||||||
string str => str,
|
}
|
||||||
AnyOf<string, StringPattern>[] stringPatterns => FormatBodies(stringPatterns.Select(p => p.GetPattern())),
|
|
||||||
byte[] bytes => $"byte[{bytes.Length}] {{...}}",
|
if (body is string str)
|
||||||
JToken jToken => jToken.ToString(Formatting.None),
|
{
|
||||||
_ => JToken.FromObject(body).ToString(Formatting.None)
|
return str;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (body is AnyOf<string, StringPattern>[] stringPatterns)
|
||||||
|
{
|
||||||
|
return FormatBodies(stringPatterns.Select(p => p.GetPattern()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body is byte[] bytes)
|
||||||
|
{
|
||||||
|
return $"byte[{bytes.Length}] {{...}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body is JToken jToken)
|
||||||
|
{
|
||||||
|
return jToken.ToString(Formatting.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.IO.FileNotFoundException : Could not load file or assembly 'System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
|
||||||
|
var typeName = body.GetType().FullName;
|
||||||
|
if (typeName == "System.Text.Json.JsonElement")
|
||||||
|
{
|
||||||
|
return ((dynamic)body).GetRawText();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName == "System.Text.Json.JsonDocument")
|
||||||
|
{
|
||||||
|
return ((dynamic)body).RootElement.GetRawText();
|
||||||
|
}
|
||||||
|
|
||||||
|
return JToken.FromObject(body).ToString(Formatting.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? FormatBodies(IEnumerable<object?> bodies)
|
private static string? FormatBodies(IEnumerable<object?> bodies)
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using AnyOfTypes;
|
||||||
|
using Json.Path;
|
||||||
|
using Stef.Validation;
|
||||||
|
using WireMock.Extensions;
|
||||||
|
using WireMock.Models;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SystemTextJsonPathMatcher - behaves the same as JsonPathMatcher but uses System.Text.Json and Json.Path instead of Newtonsoft.Json.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="ISystemTextJsonPathMatcher" />
|
||||||
|
public class SystemTextJsonPathMatcher : ISystemTextJsonPathMatcher
|
||||||
|
{
|
||||||
|
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SystemTextJsonPathMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="patterns">The patterns.</param>
|
||||||
|
public SystemTextJsonPathMatcher(params string[] patterns)
|
||||||
|
: this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns.ToAnyOfPatterns())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SystemTextJsonPathMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="patterns">The patterns.</param>
|
||||||
|
public SystemTextJsonPathMatcher(params AnyOf<string, StringPattern>[] patterns)
|
||||||
|
: this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SystemTextJsonPathMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
||||||
|
/// <param name="patterns">The patterns.</param>
|
||||||
|
public SystemTextJsonPathMatcher(
|
||||||
|
MatchBehaviour matchBehaviour,
|
||||||
|
MatchOperator matchOperator = MatchOperator.Or,
|
||||||
|
params AnyOf<string, StringPattern>[] patterns)
|
||||||
|
{
|
||||||
|
_patterns = Guard.NotNull(patterns);
|
||||||
|
MatchBehaviour = matchBehaviour;
|
||||||
|
MatchOperator = matchOperator;
|
||||||
|
Value = patterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public MatchResult IsMatch(string? input)
|
||||||
|
{
|
||||||
|
var score = MatchScores.Mismatch;
|
||||||
|
Exception? exception = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(input))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var node = JsonNode.Parse(input!);
|
||||||
|
score = IsMatchInternal(node);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MatchResult.From(Name, MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public MatchResult IsMatch(object? input)
|
||||||
|
{
|
||||||
|
var score = MatchScores.Mismatch;
|
||||||
|
Exception? exception = null;
|
||||||
|
|
||||||
|
// When input is null or byte[], return Mismatch.
|
||||||
|
if (input != null && input is not byte[])
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JsonNode? node = input switch
|
||||||
|
{
|
||||||
|
JsonNode jsonNode => jsonNode,
|
||||||
|
string str => JsonNode.Parse(str),
|
||||||
|
_ => JsonNode.Parse(JsonSerializer.Serialize(input))
|
||||||
|
};
|
||||||
|
|
||||||
|
score = IsMatchInternal(node);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MatchResult.From(Name, MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
|
{
|
||||||
|
return _patterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public MatchOperator MatchOperator { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => nameof(SystemTextJsonPathMatcher);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string GetCSharpCodeArguments()
|
||||||
|
{
|
||||||
|
return $"new {Name}" +
|
||||||
|
$"(" +
|
||||||
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
|
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
||||||
|
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
|
||||||
|
$")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private double IsMatchInternal(JsonNode? node)
|
||||||
|
{
|
||||||
|
// JsonPath.Net requires the node to be inside an object or array for filter expressions.
|
||||||
|
// Similar to JsonPathMatcher's ConvertJTokenToJArrayIfNeeded, wrap a plain object in an array
|
||||||
|
// when it's an object with a single non-array child property.
|
||||||
|
var evaluationNode = WrapIfNeeded(node);
|
||||||
|
|
||||||
|
var values = _patterns
|
||||||
|
.Select(pattern =>
|
||||||
|
{
|
||||||
|
var path = JsonPath.Parse(pattern.GetPattern());
|
||||||
|
var result = path.Evaluate(evaluationNode);
|
||||||
|
return result.Matches is { Count: > 0 };
|
||||||
|
})
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return MatchScores.ToScore(values, MatchOperator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mirrors JsonPathMatcher.ConvertJTokenToJArrayIfNeeded:
|
||||||
|
// If the node is an object with exactly one property whose value is not already an array,
|
||||||
|
// wrap that value in an array so that filter expressions (e.g. [?(@.x == y)]) can match.
|
||||||
|
private static JsonNode? WrapIfNeeded(JsonNode? node)
|
||||||
|
{
|
||||||
|
if (node is not JsonObject obj)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = obj.ToList();
|
||||||
|
if (properties.Count != 1)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
var single = properties[0];
|
||||||
|
if (single.Value is JsonArray)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
var clonedValue = JsonNode.Parse(single.Value?.ToJsonString() ?? "null");
|
||||||
|
return new JsonObject
|
||||||
|
{
|
||||||
|
[single.Key] = new JsonArray(clonedValue)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Description>A SystemTextJsonPathMatcher which can be used to match WireMock.Net Requests using JsonPath.Net.</Description>
|
||||||
|
<AssemblyTitle>WireMock.Net.Matchers.SystemTextJsonPath</AssemblyTitle>
|
||||||
|
<Authors>Stef Heyenrath</Authors>
|
||||||
|
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<PackageTags>wiremock;matchers;matcher;jsonpath;systemtextjson</PackageTags>
|
||||||
|
<RootNamespace>WireMock</RootNamespace>
|
||||||
|
<PackageId>WireMock.Net.Matchers.SystemTextJsonPath</PackageId>
|
||||||
|
<ProjectGuid>{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}</ProjectGuid>
|
||||||
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
||||||
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||||
|
<SignAssembly>true</SignAssembly>
|
||||||
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
|
<!--<DelaySign>true</DelaySign>-->
|
||||||
|
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
|
||||||
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\WireMock.Net.Shared\WireMock.Net.Shared.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="JsonPath.Net" Version="3.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using JsonConverter.Abstractions;
|
||||||
using System.Collections.Generic;
|
using JsonConverter.Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using WireMock.Matchers.Helpers;
|
using WireMock.Matchers.Helpers;
|
||||||
using WireMock.Models.Mime;
|
using WireMock.Models.Mime;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
@@ -15,6 +16,8 @@ public class MimePartMatcher : IMimePartMatcher
|
|||||||
{
|
{
|
||||||
private readonly IList<(string Name, Func<IMimePartData, MatchResult> func)> _matcherFunctions;
|
private readonly IList<(string Name, Func<IMimePartData, MatchResult> func)> _matcherFunctions;
|
||||||
|
|
||||||
|
private readonly IJsonConverter _jsonConverter;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => nameof(MimePartMatcher);
|
public string Name => nameof(MimePartMatcher);
|
||||||
|
|
||||||
@@ -41,7 +44,8 @@ public class MimePartMatcher : IMimePartMatcher
|
|||||||
IStringMatcher? contentTypeMatcher,
|
IStringMatcher? contentTypeMatcher,
|
||||||
IStringMatcher? contentDispositionMatcher,
|
IStringMatcher? contentDispositionMatcher,
|
||||||
IStringMatcher? contentTransferEncodingMatcher,
|
IStringMatcher? contentTransferEncodingMatcher,
|
||||||
IMatcher? contentMatcher
|
IMatcher? contentMatcher,
|
||||||
|
IJsonConverter? jsonConverter = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
@@ -49,6 +53,7 @@ public class MimePartMatcher : IMimePartMatcher
|
|||||||
ContentDispositionMatcher = contentDispositionMatcher;
|
ContentDispositionMatcher = contentDispositionMatcher;
|
||||||
ContentTransferEncodingMatcher = contentTransferEncodingMatcher;
|
ContentTransferEncodingMatcher = contentTransferEncodingMatcher;
|
||||||
ContentMatcher = contentMatcher;
|
ContentMatcher = contentMatcher;
|
||||||
|
_jsonConverter = jsonConverter ?? new NewtonsoftJsonConverter();
|
||||||
|
|
||||||
_matcherFunctions = [];
|
_matcherFunctions = [];
|
||||||
if (ContentTypeMatcher != null)
|
if (ContentTypeMatcher != null)
|
||||||
@@ -107,7 +112,8 @@ public class MimePartMatcher : IMimePartMatcher
|
|||||||
ContentType = GetContentTypeAsString(mimePart.ContentType),
|
ContentType = GetContentTypeAsString(mimePart.ContentType),
|
||||||
DeserializeJson = true,
|
DeserializeJson = true,
|
||||||
ContentEncoding = null, // mimePart.ContentType?.CharsetEncoding.ToString(),
|
ContentEncoding = null, // mimePart.ContentType?.CharsetEncoding.ToString(),
|
||||||
DecompressGZipAndDeflate = true
|
DecompressGZipAndDeflate = true,
|
||||||
|
DefaultJsonConverter = _jsonConverter
|
||||||
};
|
};
|
||||||
|
|
||||||
var bodyData = BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false).GetAwaiter().GetResult();
|
var bodyData = BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Stef.Validation" Version="0.2.0" />
|
<PackageReference Include="Stef.Validation" Version="0.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
|
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using JsonConverter.Abstractions;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Http;
|
namespace WireMock.Http;
|
||||||
@@ -15,7 +14,8 @@ internal static class HttpResponseMessageHelper
|
|||||||
Uri originalUri,
|
Uri originalUri,
|
||||||
bool deserializeJson,
|
bool deserializeJson,
|
||||||
bool decompressGzipAndDeflate,
|
bool decompressGzipAndDeflate,
|
||||||
bool deserializeFormUrlEncoded)
|
bool deserializeFormUrlEncoded,
|
||||||
|
IJsonConverter jsonConverter)
|
||||||
{
|
{
|
||||||
var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode };
|
var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode };
|
||||||
|
|
||||||
@@ -45,7 +45,8 @@ internal static class HttpResponseMessageHelper
|
|||||||
DeserializeJson = deserializeJson,
|
DeserializeJson = deserializeJson,
|
||||||
ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
|
ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
|
||||||
DecompressGZipAndDeflate = decompressGzipAndDeflate,
|
DecompressGZipAndDeflate = decompressGzipAndDeflate,
|
||||||
DeserializeFormUrlEncoded = deserializeFormUrlEncoded
|
DeserializeFormUrlEncoded = deserializeFormUrlEncoded,
|
||||||
|
DefaultJsonConverter = jsonConverter
|
||||||
};
|
};
|
||||||
responseMessage.BodyData = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);
|
responseMessage.BodyData = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generic AbstractSystemTextJsonPartialMatcher - uses System.Text.Json instead of Newtonsoft.Json.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class AbstractSystemTextJsonPartialMatcher : SystemTextJsonMatcher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractSystemTextJsonPartialMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
protected AbstractSystemTextJsonPartialMatcher(string value, bool ignoreCase = false, bool regex = false)
|
||||||
|
: base(value, ignoreCase, regex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractSystemTextJsonPartialMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
protected AbstractSystemTextJsonPartialMatcher(object value, bool ignoreCase = false, bool regex = false)
|
||||||
|
: base(value, ignoreCase, regex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractSystemTextJsonPartialMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
protected AbstractSystemTextJsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false)
|
||||||
|
: base(matchBehaviour, value, ignoreCase, regex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool IsMatch(JsonElement value, JsonElement? input)
|
||||||
|
{
|
||||||
|
if (input == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputElement = input.Value;
|
||||||
|
|
||||||
|
// Regex on a string value
|
||||||
|
if (Regex && value.ValueKind == JsonValueKind.String)
|
||||||
|
{
|
||||||
|
var valueAsString = value.GetString()!;
|
||||||
|
var inputAsString = GetStringValue(inputElement);
|
||||||
|
|
||||||
|
var (valid, result) = RegexUtils.MatchRegex(valueAsString, inputAsString);
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guid comparison: both strings, both parseable as Guid
|
||||||
|
if (value.ValueKind == JsonValueKind.String && inputElement.ValueKind == JsonValueKind.String)
|
||||||
|
{
|
||||||
|
var valueStr = value.GetString()!;
|
||||||
|
var inputStr = inputElement.GetString()!;
|
||||||
|
if (Guid.TryParse(valueStr, out var vg) && Guid.TryParse(inputStr, out var ig))
|
||||||
|
{
|
||||||
|
return IsMatch(vg.ToString(), ig.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type mismatch (after regex/guid checks)
|
||||||
|
if (value.ValueKind != inputElement.ValueKind)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (value.ValueKind)
|
||||||
|
{
|
||||||
|
case JsonValueKind.Object:
|
||||||
|
{
|
||||||
|
var nestedValues = value.EnumerateObject().ToArray();
|
||||||
|
if (nestedValues.Length == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nestedValues.All(pair =>
|
||||||
|
{
|
||||||
|
var selected = SelectElement(inputElement, pair.Name);
|
||||||
|
return selected != null && IsMatch(pair.Value, selected.Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case JsonValueKind.Array:
|
||||||
|
{
|
||||||
|
var valuesArray = value.EnumerateArray().ToArray();
|
||||||
|
if (valuesArray.Length == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenArray = inputElement.EnumerateArray().ToArray();
|
||||||
|
if (tokenArray.Length == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valuesArray.All(subFilter => tokenArray.Any(subToken => IsMatch(subFilter, subToken)));
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return IsMatch(GetStringValue(value), GetStringValue(inputElement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if two strings are a match (matching can be done exact or wildcard).
|
||||||
|
/// </summary>
|
||||||
|
protected abstract bool IsMatch(string value, string input);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Selects a <see cref="JsonElement"/> from an object using a key that may be a plain property name,
|
||||||
|
/// a dotted path (e.g. "a.b.c") or bracket notation (e.g. "['name.with.dot']"),
|
||||||
|
/// mirroring Newtonsoft's <c>SelectToken</c> + direct indexer fallback.
|
||||||
|
/// </summary>
|
||||||
|
private static JsonElement? SelectElement(JsonElement input, string key)
|
||||||
|
{
|
||||||
|
if (input.ValueKind != JsonValueKind.Object)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct property access (also handles keys containing colons or dots that are literal property names)
|
||||||
|
if (input.TryGetProperty(key, out var direct))
|
||||||
|
{
|
||||||
|
return direct;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bracket notation: ['property.name.with.dots']
|
||||||
|
if (key.StartsWith("['") && key.EndsWith("']"))
|
||||||
|
{
|
||||||
|
var propertyName = key.Substring(2, key.Length - 4);
|
||||||
|
return input.TryGetProperty(propertyName, out var bracketValue) ? bracketValue : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dotted path: a.b.c
|
||||||
|
if (key.Contains('.'))
|
||||||
|
{
|
||||||
|
var parts = key.Split('.');
|
||||||
|
var current = input;
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
if (current.ValueKind != JsonValueKind.Object || !current.TryGetProperty(part, out var next))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetStringValue(JsonElement element)
|
||||||
|
{
|
||||||
|
return element.ValueKind == JsonValueKind.String
|
||||||
|
? element.GetString()!
|
||||||
|
: element.GetRawText();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
@@ -13,9 +12,8 @@ namespace WireMock.Matchers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// JsonPathMatcher
|
/// JsonPathMatcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="IStringMatcher" />
|
/// <seealso cref="IJsonPathMatcher" />
|
||||||
/// <seealso cref="IObjectMatcher" />
|
public class JsonPathMatcher : IJsonPathMatcher
|
||||||
public class JsonPathMatcher : IStringMatcher, IObjectMatcher
|
|
||||||
{
|
{
|
||||||
private readonly AnyOf<string, StringPattern>[] _patterns;
|
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
using System.Collections;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
|
using WireMock.Serialization;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
using JsonUtils = WireMock.Util.JsonUtils;
|
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
@@ -31,6 +32,11 @@ public class JsonMatcher : IJsonMatcher
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Regex { get; }
|
public bool Regex { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore array order when comparing
|
||||||
|
/// </summary>
|
||||||
|
public bool IgnoreArrayOrder { get; }
|
||||||
|
|
||||||
private readonly JToken _valueAsJToken;
|
private readonly JToken _valueAsJToken;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -39,7 +45,8 @@ public class JsonMatcher : IJsonMatcher
|
|||||||
/// <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)
|
/// <param name="ignoreArrayOrder">Ignore array element order when comparing.</param>
|
||||||
|
public JsonMatcher(string value, bool ignoreCase = false, bool regex = false, bool ignoreArrayOrder = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, regex, ignoreArrayOrder)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +56,8 @@ public class JsonMatcher : IJsonMatcher
|
|||||||
/// <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)
|
/// <param name="ignoreArrayOrder">Ignore array element order when comparing.</param>
|
||||||
|
public JsonMatcher(object value, bool ignoreCase = false, bool regex = false, bool ignoreArrayOrder = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, regex, ignoreArrayOrder)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,16 +68,18 @@ public class JsonMatcher : IJsonMatcher
|
|||||||
/// <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)
|
/// <param name="ignoreArrayOrder">Ignore array element order when comparing.</param>
|
||||||
|
public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false, bool ignoreArrayOrder = false)
|
||||||
{
|
{
|
||||||
Guard.NotNull(value);
|
Guard.NotNull(value);
|
||||||
|
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
IgnoreCase = ignoreCase;
|
IgnoreCase = ignoreCase;
|
||||||
Regex = regex;
|
Regex = regex;
|
||||||
|
IgnoreArrayOrder = ignoreArrayOrder;
|
||||||
|
|
||||||
Value = value;
|
Value = value;
|
||||||
_valueAsJToken = JsonUtils.ConvertValueToJToken(value);
|
_valueAsJToken = ConvertValueToJToken(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -83,7 +93,7 @@ public class JsonMatcher : IJsonMatcher
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var inputAsJToken = JsonUtils.ConvertValueToJToken(input);
|
var inputAsJToken = ConvertValueToJToken(input);
|
||||||
|
|
||||||
var match = IsMatch(RenameJToken(_valueAsJToken), RenameJToken(inputAsJToken));
|
var match = IsMatch(RenameJToken(_valueAsJToken), RenameJToken(inputAsJToken));
|
||||||
score = MatchScores.ToScore(match);
|
score = MatchScores.ToScore(match);
|
||||||
@@ -103,9 +113,10 @@ public class JsonMatcher : IJsonMatcher
|
|||||||
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)}, " +
|
||||||
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreArrayOrder)}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +193,13 @@ public class JsonMatcher : IJsonMatcher
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IgnoreArrayOrder)
|
||||||
|
{
|
||||||
|
// Sort both arrays by their string representation and compare
|
||||||
|
valueArray = valueArray.OrderBy(t => t.ToString()).ToArray();
|
||||||
|
inputArray = inputArray.OrderBy(t => t.ToString()).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
return !valueArray.Where((valueToken, index) => !IsMatch(valueToken, inputArray[index])).Any();
|
return !valueArray.Where((valueToken, index) => !IsMatch(valueToken, inputArray[index])).Any();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -241,6 +259,18 @@ public class JsonMatcher : IJsonMatcher
|
|||||||
return new JObject(renamedProperties);
|
return new JObject(renamedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static JToken ConvertValueToJToken(object value)
|
||||||
|
{
|
||||||
|
// Check if JToken, string, IEnumerable or object
|
||||||
|
return value switch
|
||||||
|
{
|
||||||
|
JToken tokenValue => tokenValue,
|
||||||
|
string stringValue => JsonConvert.DeserializeObject<JToken>(stringValue, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone)!,
|
||||||
|
IEnumerable enumerableValue => JArray.FromObject(enumerableValue),
|
||||||
|
_ => JObject.FromObject(value),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static string? ToUpper(string? input)
|
private static string? ToUpper(string? input)
|
||||||
{
|
{
|
||||||
return input?.ToUpperInvariant();
|
return input?.ToUpperInvariant();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Matchers.Helpers;
|
using WireMock.Matchers.Helpers;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|||||||
@@ -0,0 +1,299 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Stef.Validation;
|
||||||
|
using WireMock.Extensions;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SystemTextJsonMatcher - behaves the same as <see cref="JsonMatcher"/> but uses System.Text.Json instead of Newtonsoft.Json.
|
||||||
|
/// </summary>
|
||||||
|
public class SystemTextJsonMatcher : IJsonMatcher
|
||||||
|
{
|
||||||
|
private static readonly JsonSerializerOptions DefaultSerializerOptions = new()
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = false
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual string Name => nameof(SystemTextJsonMatcher);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object Value { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/>
|
||||||
|
public bool IgnoreCase { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Support Regex
|
||||||
|
/// </summary>
|
||||||
|
public bool Regex { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore array order when comparing
|
||||||
|
/// </summary>
|
||||||
|
public bool IgnoreArrayOrder { get; }
|
||||||
|
|
||||||
|
private readonly JsonElement _valueAsJsonElement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SystemTextJsonMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <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="regex">Support Regex.</param>
|
||||||
|
/// <param name="ignoreArrayOrder">Ignore array element order when comparing.</param>
|
||||||
|
public SystemTextJsonMatcher(string value, bool ignoreCase = false, bool regex = false, bool ignoreArrayOrder = false)
|
||||||
|
: this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, regex, ignoreArrayOrder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SystemTextJsonMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <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="regex">Support Regex.</param>
|
||||||
|
/// <param name="ignoreArrayOrder">Ignore array element order when comparing.</param>
|
||||||
|
public SystemTextJsonMatcher(object value, bool ignoreCase = false, bool regex = false, bool ignoreArrayOrder = false)
|
||||||
|
: this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, regex, ignoreArrayOrder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SystemTextJsonMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="matchBehaviour">The match behaviour.</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="regex">Support Regex.</param>
|
||||||
|
/// <param name="ignoreArrayOrder">Ignore array element order when comparing.</param>
|
||||||
|
public SystemTextJsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false, bool ignoreArrayOrder = false)
|
||||||
|
{
|
||||||
|
Guard.NotNull(value);
|
||||||
|
|
||||||
|
MatchBehaviour = matchBehaviour;
|
||||||
|
IgnoreCase = ignoreCase;
|
||||||
|
Regex = regex;
|
||||||
|
IgnoreArrayOrder = ignoreArrayOrder;
|
||||||
|
|
||||||
|
Value = value;
|
||||||
|
_valueAsJsonElement = ConvertToJsonElement(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public MatchResult IsMatch(object? input)
|
||||||
|
{
|
||||||
|
var score = MatchScores.Mismatch;
|
||||||
|
Exception? error = null;
|
||||||
|
|
||||||
|
// When input is null or byte[], return Mismatch.
|
||||||
|
if (input != null && input is not byte[])
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var inputAsJsonElement = ConvertToJsonElement(input);
|
||||||
|
|
||||||
|
var match = IsMatch(NormalizeElement(_valueAsJsonElement), NormalizeElement(inputAsJsonElement));
|
||||||
|
score = MatchScores.ToScore(match);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
error = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MatchResult.From(Name, MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual string GetCSharpCodeArguments()
|
||||||
|
{
|
||||||
|
return $"new {Name}" +
|
||||||
|
$"(" +
|
||||||
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
|
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
|
||||||
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
|
||||||
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}, " +
|
||||||
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreArrayOrder)}" +
|
||||||
|
$")";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the input against the matcher value
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool IsMatch(JsonElement value, JsonElement? input)
|
||||||
|
{
|
||||||
|
if (input == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputElement = input.Value;
|
||||||
|
|
||||||
|
// If using Regex and the value is a string, use the MatchRegex method.
|
||||||
|
if (Regex && value.ValueKind == JsonValueKind.String)
|
||||||
|
{
|
||||||
|
var valueAsString = value.GetString()!;
|
||||||
|
var inputAsString = inputElement.ValueKind == JsonValueKind.String
|
||||||
|
? inputElement.GetString()!
|
||||||
|
: inputElement.GetRawText();
|
||||||
|
|
||||||
|
var (valid, result) = RegexUtils.MatchRegex(valueAsString, inputAsString);
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the value is a Guid (string) and input is a string, or vice versa, compare as strings.
|
||||||
|
if (value.ValueKind == JsonValueKind.String && inputElement.ValueKind == JsonValueKind.String)
|
||||||
|
{
|
||||||
|
var valueStr = value.GetString()!;
|
||||||
|
var inputStr = inputElement.GetString()!;
|
||||||
|
|
||||||
|
if (Guid.TryParse(valueStr, out var valueGuid) && Guid.TryParse(inputStr, out var inputGuid))
|
||||||
|
{
|
||||||
|
return valueGuid == inputGuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (value.ValueKind)
|
||||||
|
{
|
||||||
|
case JsonValueKind.Object:
|
||||||
|
{
|
||||||
|
if (inputElement.ValueKind != JsonValueKind.Object)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var valueProperties = value.EnumerateObject().ToDictionary(p => p.Name, p => p.Value);
|
||||||
|
var inputProperties = inputElement.EnumerateObject().ToDictionary(p => p.Name, p => p.Value);
|
||||||
|
|
||||||
|
if (valueProperties.Count != inputProperties.Count)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pair in valueProperties)
|
||||||
|
{
|
||||||
|
if (!inputProperties.TryGetValue(pair.Key, out var inputPropValue))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsMatch(pair.Value, inputPropValue))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case JsonValueKind.Array:
|
||||||
|
{
|
||||||
|
if (inputElement.ValueKind != JsonValueKind.Array)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var valueArray = value.EnumerateArray().ToArray();
|
||||||
|
var inputArray = inputElement.EnumerateArray().ToArray();
|
||||||
|
|
||||||
|
if (valueArray.Length != inputArray.Length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IgnoreArrayOrder)
|
||||||
|
{
|
||||||
|
// Sort both arrays by their string representation and compare
|
||||||
|
valueArray = valueArray.OrderBy(e => e.GetRawText()).ToArray();
|
||||||
|
inputArray = inputArray.OrderBy(e => e.GetRawText()).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return !valueArray.Where((valueToken, index) => !IsMatch(valueToken, inputArray[index])).Any();
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return value.GetRawText() == inputElement.GetRawText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonElement NormalizeElement(JsonElement element)
|
||||||
|
{
|
||||||
|
if (!IgnoreCase)
|
||||||
|
{
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
var normalized = NormalizeValue(element);
|
||||||
|
return ConvertToJsonElement(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
private object NormalizeValue(JsonElement element)
|
||||||
|
{
|
||||||
|
switch (element.ValueKind)
|
||||||
|
{
|
||||||
|
case JsonValueKind.Object:
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, object?>();
|
||||||
|
foreach (var prop in element.EnumerateObject())
|
||||||
|
{
|
||||||
|
var normalizedKey = prop.Name.ToUpperInvariant();
|
||||||
|
dict[normalizedKey] = NormalizeValue(prop.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
case JsonValueKind.Array:
|
||||||
|
{
|
||||||
|
if (Regex)
|
||||||
|
{
|
||||||
|
return element.EnumerateArray().Select(e => (object)e.GetRawText()).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return element.EnumerateArray().Select(NormalizeValue).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
case JsonValueKind.String:
|
||||||
|
{
|
||||||
|
var str = element.GetString()!;
|
||||||
|
return Regex ? str : str.ToUpperInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return element.GetRawText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JsonElement ConvertToJsonElement(object value)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case JsonElement jsonElement:
|
||||||
|
return jsonElement;
|
||||||
|
|
||||||
|
case JsonDocument jsonDocument:
|
||||||
|
return jsonDocument.RootElement;
|
||||||
|
|
||||||
|
case string stringValue:
|
||||||
|
return JsonDocument.Parse(stringValue).RootElement;
|
||||||
|
|
||||||
|
case IEnumerable enumerableValue when value is not string:
|
||||||
|
return JsonSerializer.SerializeToElement(enumerableValue, DefaultSerializerOptions);
|
||||||
|
|
||||||
|
default:
|
||||||
|
var json = JsonSerializer.Serialize(value, DefaultSerializerOptions);
|
||||||
|
return JsonDocument.Parse(json).RootElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using WireMock.Extensions;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SystemTextJsonPartialMatcher - uses System.Text.Json instead of Newtonsoft.Json.
|
||||||
|
/// </summary>
|
||||||
|
public class SystemTextJsonPartialMatcher : AbstractSystemTextJsonPartialMatcher
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string Name => nameof(SystemTextJsonPartialMatcher);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public SystemTextJsonPartialMatcher(string value, bool ignoreCase = false, bool regex = false)
|
||||||
|
: base(value, ignoreCase, regex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public SystemTextJsonPartialMatcher(object value, bool ignoreCase = false, bool regex = false)
|
||||||
|
: base(value, ignoreCase, regex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public SystemTextJsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false)
|
||||||
|
: base(matchBehaviour, value, ignoreCase, regex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool IsMatch(string value, string input)
|
||||||
|
{
|
||||||
|
var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, IgnoreCase, MatchOperator.Or, value);
|
||||||
|
return exactStringMatcher.IsMatch(input).IsPerfect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string GetCSharpCodeArguments()
|
||||||
|
{
|
||||||
|
return $"new {Name}" +
|
||||||
|
$"(" +
|
||||||
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
|
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
|
||||||
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
|
||||||
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
|
||||||
|
$")";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using WireMock.Extensions;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SystemTextJsonPartialWildcardMatcher - uses System.Text.Json instead of Newtonsoft.Json.
|
||||||
|
/// </summary>
|
||||||
|
public class SystemTextJsonPartialWildcardMatcher : AbstractSystemTextJsonPartialMatcher
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string Name => nameof(SystemTextJsonPartialWildcardMatcher);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public SystemTextJsonPartialWildcardMatcher(string value, bool ignoreCase = false, bool regex = false)
|
||||||
|
: base(value, ignoreCase, regex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public SystemTextJsonPartialWildcardMatcher(object value, bool ignoreCase = false, bool regex = false)
|
||||||
|
: base(value, ignoreCase, regex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public SystemTextJsonPartialWildcardMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false)
|
||||||
|
: base(matchBehaviour, value, ignoreCase, regex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool IsMatch(string value, string input)
|
||||||
|
{
|
||||||
|
var wildcardStringMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, value, IgnoreCase);
|
||||||
|
return wildcardStringMatcher.IsMatch(input).IsPerfect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string GetCSharpCodeArguments()
|
||||||
|
{
|
||||||
|
return $"new {Name}" +
|
||||||
|
$"(" +
|
||||||
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
|
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
|
||||||
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
|
||||||
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
|
||||||
|
$")";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,7 +53,8 @@ internal class OwinRequestMapper : IOwinRequestMapper
|
|||||||
ContentType = request.ContentType,
|
ContentType = request.ContentType,
|
||||||
DeserializeJson = !options.DisableJsonBodyParsing.GetValueOrDefault(false),
|
DeserializeJson = !options.DisableJsonBodyParsing.GetValueOrDefault(false),
|
||||||
ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
|
ContentEncoding = contentEncodingHeader?.FirstOrDefault(),
|
||||||
DecompressGZipAndDeflate = !options.DisableRequestBodyDecompressing.GetValueOrDefault(false)
|
DecompressGZipAndDeflate = !options.DisableRequestBodyDecompressing.GetValueOrDefault(false),
|
||||||
|
DefaultJsonConverter = options.DefaultJsonSerializer
|
||||||
};
|
};
|
||||||
|
|
||||||
body = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);
|
body = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
using WireMock.Owin.ActivityTracing;
|
using WireMock.Owin.ActivityTracing;
|
||||||
using WireMock.Serialization;
|
using WireMock.Serialization;
|
||||||
@@ -42,7 +41,7 @@ internal class WireMockMiddlewareLogger(
|
|||||||
if (_options.SaveUnmatchedRequests == true && match?.RequestMatchResult is not { IsPerfectMatch: true })
|
if (_options.SaveUnmatchedRequests == true && match?.RequestMatchResult is not { IsPerfectMatch: true })
|
||||||
{
|
{
|
||||||
var filename = $"{logEntry.Guid}.LogEntry.json";
|
var filename = $"{logEntry.Guid}.LogEntry.json";
|
||||||
_options.FileSystemHandler?.WriteUnmatchedRequest(filename, JsonUtils.Serialize(logEntry));
|
_options.FileSystemHandler?.WriteUnmatchedRequest(filename, _options.DefaultJsonSerializer.Serialize(logEntry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ using System.Runtime.CompilerServices;
|
|||||||
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
|
|
||||||
// Needed for Moq in the UnitTest project
|
// Needed for Moq in the UnitTest project
|
||||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
|
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
|
||||||
@@ -48,7 +48,8 @@ internal class ProxyHelper(WireMockServerSettings settings)
|
|||||||
originalUri,
|
originalUri,
|
||||||
deserializeJson,
|
deserializeJson,
|
||||||
decompressGzipAndDeflate,
|
decompressGzipAndDeflate,
|
||||||
deserializeFormUrlEncoded
|
deserializeFormUrlEncoded,
|
||||||
|
_settings.DefaultJsonSerializer
|
||||||
).ConfigureAwait(false);
|
).ConfigureAwait(false);
|
||||||
|
|
||||||
IMapping? newMapping = null;
|
IMapping? newMapping = null;
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JsonConverter.Abstractions;
|
using JsonConverter.Abstractions;
|
||||||
|
using JsonConverter.Newtonsoft.Json;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
|
using WireMock.Serialization;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
@@ -119,11 +121,13 @@ public partial class Response
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IResponseBuilder WithBody(string body, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null)
|
public IResponseBuilder WithBody(string body, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null, IJsonConverter? jsonConverter = null, JsonConverterOptions? options = null)
|
||||||
{
|
{
|
||||||
Guard.NotNull(body);
|
Guard.NotNull(body);
|
||||||
|
|
||||||
encoding ??= Encoding.UTF8;
|
encoding ??= Encoding.UTF8;
|
||||||
|
jsonConverter ??= new NewtonsoftJsonConverter();
|
||||||
|
options ??= JsonSerializationConstants.JsonConverterOptionsWithDateParsingNone;
|
||||||
|
|
||||||
ResponseMessage.BodyDestination = destination;
|
ResponseMessage.BodyDestination = destination;
|
||||||
ResponseMessage.BodyData = new BodyData
|
ResponseMessage.BodyData = new BodyData
|
||||||
@@ -140,7 +144,7 @@ public partial class Response
|
|||||||
|
|
||||||
case BodyDestinationFormat.Json:
|
case BodyDestinationFormat.Json:
|
||||||
ResponseMessage.BodyData.DetectedBodyType = BodyType.Json;
|
ResponseMessage.BodyData.DetectedBodyType = BodyType.Json;
|
||||||
ResponseMessage.BodyData.BodyAsJson = JsonUtils.DeserializeObject(body);
|
ResponseMessage.BodyData.BodyAsJson = jsonConverter.Deserialize<object>(body, options);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ public partial class Response : IResponseBuilder
|
|||||||
|
|
||||||
if (ProxyAndRecordSettings != null && _httpClientForProxy != null)
|
if (ProxyAndRecordSettings != null && _httpClientForProxy != null)
|
||||||
{
|
{
|
||||||
string RemoveFirstOccurrence(string source, string find)
|
static string RemoveFirstOccurrence(string source, string find)
|
||||||
{
|
{
|
||||||
int place = source.IndexOf(find, StringComparison.OrdinalIgnoreCase);
|
int place = source.IndexOf(find, StringComparison.OrdinalIgnoreCase);
|
||||||
return place >= 0 ? source.Remove(place, find.Length) : source;
|
return place >= 0 ? source.Remove(place, find.Length) : source;
|
||||||
@@ -265,7 +265,7 @@ public partial class Response : IResponseBuilder
|
|||||||
var decoded = await protoBufMatcher.DecodeAsync(requestMessage.BodyData?.BodyAsBytes).ConfigureAwait(false);
|
var decoded = await protoBufMatcher.DecodeAsync(requestMessage.BodyData?.BodyAsBytes).ConfigureAwait(false);
|
||||||
if (decoded != null)
|
if (decoded != null)
|
||||||
{
|
{
|
||||||
requestMessageImplementation.BodyAsJson = JsonUtils.ConvertValueToJToken(decoded);
|
requestMessageImplementation.BodyAsJson = settings.DefaultJsonSerializer.ToJsonToken(decoded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,31 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using JsonConverter.Abstractions;
|
using JsonConverter.Abstractions;
|
||||||
using Newtonsoft.Json;
|
using JsonConverter.Abstractions.Models;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
#if NETSTANDARD2_0_OR_GREATER || NETCOREAPP3_1_OR_GREATER || NET6_0_OR_GREATER || NET461
|
|
||||||
using System.Text.Json;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace WireMock.Serialization;
|
namespace WireMock.Serialization;
|
||||||
|
|
||||||
internal class MappingSerializer(IJsonConverter jsonConverter)
|
internal class MappingSerializer(IJsonConverter jsonConverter)
|
||||||
{
|
{
|
||||||
private static readonly JsonConverterOptions JsonConverterOptions = new JsonConverterOptions
|
|
||||||
{
|
|
||||||
DateParseHandling = (int) DateParseHandling.None
|
|
||||||
};
|
|
||||||
|
|
||||||
internal T[] DeserializeJsonToArray<T>(string value)
|
internal T[] DeserializeJsonToArray<T>(string value)
|
||||||
{
|
{
|
||||||
// DeserializeObject
|
switch (JsonTypeHelper.GetJsonType(value))
|
||||||
return DeserializeObjectToArray<T>(jsonConverter.Deserialize<object>(value, JsonConverterOptions)!);
|
{
|
||||||
|
case JsonType.Array:
|
||||||
|
return jsonConverter.Deserialize<T[]>(value, JsonSerializationConstants.JsonConverterOptionsWithDateParsingNone)!;
|
||||||
|
|
||||||
|
case JsonType.Object:
|
||||||
|
var singleResult = jsonConverter.Deserialize<T>(value, JsonSerializationConstants.JsonConverterOptionsWithDateParsingNone);
|
||||||
|
return [singleResult!];
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Cannot deserialize the provided value to an array or object.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static T[] DeserializeObjectToArray<T>(object value)
|
internal T[] DeserializeObjectToArray<T>(object value)
|
||||||
{
|
{
|
||||||
if (value is JArray jArray)
|
var json = jsonConverter.Serialize(value, JsonSerializationConstants.JsonConverterOptionsWithDateParsingNone);
|
||||||
{
|
return DeserializeJsonToArray<T>(json);
|
||||||
return jArray.ToObject<T[]>()!;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value is JObject jObject)
|
|
||||||
{
|
|
||||||
var singleResult = jObject.ToObject<T>();
|
|
||||||
return [singleResult!];
|
|
||||||
}
|
|
||||||
|
|
||||||
#if NETSTANDARD2_0_OR_GREATER || NETCOREAPP3_1_OR_GREATER || NET6_0_OR_GREATER || NET461
|
|
||||||
if (value is JsonElement jElement)
|
|
||||||
{
|
|
||||||
if (jElement.ValueKind == JsonValueKind.Array)
|
|
||||||
{
|
|
||||||
return jElement.Deserialize<T[]>()!;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jElement.ValueKind == JsonValueKind.Object)
|
|
||||||
{
|
|
||||||
var singleResult = jElement.Deserialize<T>();
|
|
||||||
return [singleResult!];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
throw new InvalidOperationException("Cannot deserialize the provided value to an array or object.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,9 +106,29 @@ internal class MatcherMapper
|
|||||||
var valueForJsonPartialWildcardMatcher = matcherModel.Pattern ?? matcherModel.Patterns;
|
var valueForJsonPartialWildcardMatcher = matcherModel.Pattern ?? matcherModel.Patterns;
|
||||||
return new JsonPartialWildcardMatcher(matchBehaviour, valueForJsonPartialWildcardMatcher!, ignoreCase, useRegex);
|
return new JsonPartialWildcardMatcher(matchBehaviour, valueForJsonPartialWildcardMatcher!, ignoreCase, useRegex);
|
||||||
|
|
||||||
|
case nameof(SystemTextJsonMatcher):
|
||||||
|
var valueForSystemTextJsonMatcher = matcherModel.Pattern ?? matcherModel.Patterns;
|
||||||
|
return new SystemTextJsonMatcher(matchBehaviour, valueForSystemTextJsonMatcher!, ignoreCase, useRegex);
|
||||||
|
|
||||||
|
case nameof(SystemTextJsonPartialMatcher):
|
||||||
|
var valueForSystemTextJsonPartialMatcher = matcherModel.Pattern ?? matcherModel.Patterns;
|
||||||
|
return new SystemTextJsonPartialMatcher(matchBehaviour, valueForSystemTextJsonPartialMatcher!, ignoreCase, useRegex);
|
||||||
|
|
||||||
|
case nameof(SystemTextJsonPartialWildcardMatcher):
|
||||||
|
var valueForSystemTextJsonPartialWildcardMatcher = matcherModel.Pattern ?? matcherModel.Patterns;
|
||||||
|
return new SystemTextJsonPartialWildcardMatcher(matchBehaviour, valueForSystemTextJsonPartialWildcardMatcher!, ignoreCase, useRegex);
|
||||||
|
|
||||||
case nameof(JsonPathMatcher):
|
case nameof(JsonPathMatcher):
|
||||||
return new JsonPathMatcher(matchBehaviour, matchOperator, stringPatterns);
|
return new JsonPathMatcher(matchBehaviour, matchOperator, stringPatterns);
|
||||||
|
|
||||||
|
case "SystemTextJsonPathMatcher":
|
||||||
|
if (TypeLoader.TryLoadNewInstance<ISystemTextJsonPathMatcher>(out var systemTextJsonPathMatcher, matchBehaviour, matchOperator, stringPatterns))
|
||||||
|
{
|
||||||
|
return systemTextJsonPathMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("The 'SystemTextJsonPathMatcher' cannot be loaded. Please install the WireMock.Net.Matchers.SystemTextJsonPath package.");
|
||||||
|
|
||||||
case nameof(JmesPathMatcher):
|
case nameof(JmesPathMatcher):
|
||||||
return new JmesPathMatcher(matchBehaviour, matchOperator, stringPatterns);
|
return new JmesPathMatcher(matchBehaviour, matchOperator, stringPatterns);
|
||||||
|
|
||||||
@@ -171,6 +191,10 @@ internal class MatcherMapper
|
|||||||
model.Regex = jsonMatcher.Regex;
|
model.Regex = jsonMatcher.Regex;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SystemTextJsonMatcher stjMatcher:
|
||||||
|
model.Regex = stjMatcher.Regex;
|
||||||
|
break;
|
||||||
|
|
||||||
case XPathMatcher xpathMatcher:
|
case XPathMatcher xpathMatcher:
|
||||||
model.XmlNamespaceMap = xpathMatcher.XmlNamespaceMap;
|
model.XmlNamespaceMap = xpathMatcher.XmlNamespaceMap;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Pact.Models.V2;
|
using WireMock.Pact.Models.V2;
|
||||||
@@ -49,7 +51,7 @@ internal static class PactMapper
|
|||||||
pact.Interactions.Add(interaction);
|
pact.Interactions.Add(interaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (filename, JsonUtils.SerializeAsPactFile(pact));
|
return (filename, SerializeAsPactFile(pact));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PactRequest MapRequest(RequestModel request, string path)
|
private static PactRequest MapRequest(RequestModel request, string path)
|
||||||
@@ -152,7 +154,7 @@ internal static class PactMapper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private static object? TryDeserializeJsonStringAsObject(string? value)
|
private static object? TryDeserializeJsonStringAsObject(string? value)
|
||||||
{
|
{
|
||||||
return value != null ? JsonUtils.TryDeserializeObject<object?>(value) ?? value : null;
|
return value != null ? TryDeserializeObject<object?>(value) ?? value : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//private static string GetPatternAsStringFromMatchers(MatcherModel[]? matchers, string defaultValue)
|
//private static string GetPatternAsStringFromMatchers(MatcherModel[]? matchers, string defaultValue)
|
||||||
@@ -164,4 +166,22 @@ internal static class PactMapper
|
|||||||
|
|
||||||
// return defaultValue;
|
// return defaultValue;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
private static byte[] SerializeAsPactFile(object value)
|
||||||
|
{
|
||||||
|
var json = JsonConvert.SerializeObject(value, JsonSerializationConstants.JsonSerializerSettingsPact);
|
||||||
|
return Encoding.UTF8.GetBytes(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T? TryDeserializeObject<T>(string json)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return JsonConvert.DeserializeObject<T>(json);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using NJsonSchema;
|
using NJsonSchema;
|
||||||
using NJsonSchema.Extensions;
|
using NJsonSchema.Extensions;
|
||||||
using NSwag;
|
using NSwag;
|
||||||
@@ -281,7 +282,7 @@ internal static class SwaggerMapper
|
|||||||
if (matcher is { Name: nameof(JsonMatcher) })
|
if (matcher is { Name: nameof(JsonMatcher) })
|
||||||
{
|
{
|
||||||
var pattern = GetPatternAsStringFromMatcher(matcher);
|
var pattern = GetPatternAsStringFromMatcher(matcher);
|
||||||
if (JsonUtils.TryParseAsJObject(pattern, out var jObject))
|
if (TryParseAsJObject(pattern, out var jObject))
|
||||||
{
|
{
|
||||||
return jObject;
|
return jObject;
|
||||||
}
|
}
|
||||||
@@ -292,6 +293,39 @@ internal static class SwaggerMapper
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsJson(string? value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value!.Trim();
|
||||||
|
|
||||||
|
return (value.StartsWith("{") && value.EndsWith("}")) || (value.StartsWith("[") && value.EndsWith("]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryParseAsJObject(string? strInput, [NotNullWhen(true)] out JObject? value)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
|
||||||
|
if (!IsJson(strInput))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Try to convert this string into a JObject
|
||||||
|
value = JObject.Parse(strInput!);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetContentType(RequestModel request)
|
private static string GetContentType(RequestModel request)
|
||||||
{
|
{
|
||||||
var contentType = request.Headers?.FirstOrDefault(h => h.Name == "Content-Type");
|
var contentType = request.Headers?.FirstOrDefault(h => h.Name == "Content-Type");
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ public partial class WireMockServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
o.CorsPolicyOptions = corsPolicyOptions;
|
o.CorsPolicyOptions = corsPolicyOptions;
|
||||||
o.ClientCertificateMode = (Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode) _settings.ClientCertificateMode;
|
o.ClientCertificateMode = (Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode)_settings.ClientCertificateMode;
|
||||||
o.AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate;
|
o.AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -883,6 +883,18 @@ public partial class WireMockServer
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private T[] DeserializeRequestMessageToArray<T>(IRequestMessage requestMessage)
|
||||||
|
{
|
||||||
|
if (requestMessage.BodyData?.DetectedBodyType == BodyType.Json && requestMessage.BodyData.BodyAsJson != null)
|
||||||
|
{
|
||||||
|
var bodyAsJson = requestMessage.BodyData.BodyAsJson!;
|
||||||
|
|
||||||
|
return _mappingSerializer.DeserializeObjectToArray<T>(bodyAsJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
private static Encoding? ToEncoding(EncodingModel? encodingModel)
|
private static Encoding? ToEncoding(EncodingModel? encodingModel)
|
||||||
{
|
{
|
||||||
return encodingModel != null ? Encoding.GetEncoding(encodingModel.CodePage) : null;
|
return encodingModel != null ? Encoding.GetEncoding(encodingModel.CodePage) : null;
|
||||||
@@ -902,28 +914,16 @@ public partial class WireMockServer
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T[] DeserializeRequestMessageToArray<T>(IRequestMessage requestMessage)
|
private T DeserializeObject<T>(IRequestMessage requestMessage)
|
||||||
{
|
|
||||||
if (requestMessage.BodyData?.DetectedBodyType == BodyType.Json && requestMessage.BodyData.BodyAsJson != null)
|
|
||||||
{
|
|
||||||
var bodyAsJson = requestMessage.BodyData.BodyAsJson!;
|
|
||||||
|
|
||||||
return MappingSerializer.DeserializeObjectToArray<T>(bodyAsJson);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T DeserializeObject<T>(IRequestMessage requestMessage)
|
|
||||||
{
|
{
|
||||||
switch (requestMessage.BodyData?.DetectedBodyType)
|
switch (requestMessage.BodyData?.DetectedBodyType)
|
||||||
{
|
{
|
||||||
case BodyType.String:
|
case BodyType.String when requestMessage.BodyData?.BodyAsString != null:
|
||||||
case BodyType.FormUrlEncoded:
|
case BodyType.FormUrlEncoded when requestMessage.BodyData?.BodyAsString != null:
|
||||||
return JsonUtils.DeserializeObject<T>(requestMessage.BodyData.BodyAsString!);
|
return _settings.DefaultJsonSerializer.Deserialize<T>(requestMessage.BodyData.BodyAsString)!;
|
||||||
|
|
||||||
case BodyType.Json when requestMessage.BodyData?.BodyAsJson != null:
|
case BodyType.Json when requestMessage.BodyData?.BodyAsJson != null:
|
||||||
return ((JObject)requestMessage.BodyData.BodyAsJson).ToObject<T>()!;
|
return _settings.DefaultJsonSerializer.ParseJsonToken<T>(requestMessage.BodyData.BodyAsJson)!;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
@@ -153,7 +152,7 @@ public partial class WireMockServer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var clientIPModel = JsonUtils.ParseJTokenToObject<ClientIPModel>(requestModel.ClientIP);
|
var clientIPModel = _settings.DefaultJsonSerializer.ParseJsonToken<ClientIPModel>(requestModel.ClientIP);
|
||||||
if (clientIPModel.Matchers != null)
|
if (clientIPModel.Matchers != null)
|
||||||
{
|
{
|
||||||
requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(_matcherMapper.Map).OfType<IStringMatcher>().ToArray());
|
requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(_matcherMapper.Map).OfType<IStringMatcher>().ToArray());
|
||||||
@@ -169,7 +168,7 @@ public partial class WireMockServer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var pathModel = JsonUtils.ParseJTokenToObject<PathModel>(requestModel.Path);
|
var pathModel = _settings.DefaultJsonSerializer.ParseJsonToken<PathModel>(requestModel.Path);
|
||||||
if (pathModel.Matchers != null)
|
if (pathModel.Matchers != null)
|
||||||
{
|
{
|
||||||
var matchOperator = StringUtils.ParseMatchOperator(pathModel.MatchOperator);
|
var matchOperator = StringUtils.ParseMatchOperator(pathModel.MatchOperator);
|
||||||
@@ -185,7 +184,7 @@ public partial class WireMockServer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var urlModel = JsonUtils.ParseJTokenToObject<UrlModel>(requestModel.Url);
|
var urlModel = _settings.DefaultJsonSerializer.ParseJsonToken<UrlModel>(requestModel.Url);
|
||||||
if (urlModel.Matchers != null)
|
if (urlModel.Matchers != null)
|
||||||
{
|
{
|
||||||
var matchOperator = StringUtils.ParseMatchOperator(urlModel.MatchOperator);
|
var matchOperator = StringUtils.ParseMatchOperator(urlModel.MatchOperator);
|
||||||
@@ -273,7 +272,7 @@ public partial class WireMockServer
|
|||||||
return requestBuilder;
|
return requestBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IResponseBuilder InitResponseBuilder(ResponseModel responseModel)
|
private IResponseBuilder InitResponseBuilder(ResponseModel responseModel)
|
||||||
{
|
{
|
||||||
var responseBuilder = Response.Create();
|
var responseBuilder = Response.Create();
|
||||||
|
|
||||||
@@ -338,7 +337,7 @@ public partial class WireMockServer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var headers = JsonUtils.ParseJTokenToObject<string[]>(entry.Value);
|
var headers = _settings.DefaultJsonSerializer.ParseJsonToken<string[]>(entry.Value);
|
||||||
responseBuilder.WithHeader(entry.Key, headers);
|
responseBuilder.WithHeader(entry.Key, headers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,7 +363,7 @@ public partial class WireMockServer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var headers = JsonUtils.ParseJTokenToObject<string[]>(entry.Value);
|
var headers = _settings.DefaultJsonSerializer.ParseJsonToken<string[]>(entry.Value);
|
||||||
responseBuilder.WithTrailingHeader(entry.Key, headers);
|
responseBuilder.WithTrailingHeader(entry.Key, headers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,14 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using JsonConverter.Newtonsoft.Json;
|
||||||
|
using JsonConverter.System.Text.Json;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Constants;
|
using WireMock.Constants;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
|
using WireMock.Transformers;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
@@ -57,11 +59,9 @@ public static class WireMockServerSettingsParser
|
|||||||
DisableRequestBodyDecompressing = parser.GetBoolValue(nameof(WireMockServerSettings.DisableRequestBodyDecompressing)),
|
DisableRequestBodyDecompressing = parser.GetBoolValue(nameof(WireMockServerSettings.DisableRequestBodyDecompressing)),
|
||||||
DisableDeserializeFormUrlEncoded = parser.GetBoolValue(nameof(WireMockServerSettings.DisableDeserializeFormUrlEncoded)),
|
DisableDeserializeFormUrlEncoded = parser.GetBoolValue(nameof(WireMockServerSettings.DisableDeserializeFormUrlEncoded)),
|
||||||
DoNotSaveDynamicResponseInLogEntry = parser.GetBoolValue(nameof(WireMockServerSettings.DoNotSaveDynamicResponseInLogEntry)),
|
DoNotSaveDynamicResponseInLogEntry = parser.GetBoolValue(nameof(WireMockServerSettings.DoNotSaveDynamicResponseInLogEntry)),
|
||||||
GraphQLSchemas = parser.GetObjectValueFromJson<Dictionary<string, GraphQLSchemaDetails>>(nameof(settings.GraphQLSchemas)),
|
|
||||||
HandleRequestsSynchronously = parser.GetBoolValue(nameof(WireMockServerSettings.HandleRequestsSynchronously)),
|
HandleRequestsSynchronously = parser.GetBoolValue(nameof(WireMockServerSettings.HandleRequestsSynchronously)),
|
||||||
HostingScheme = parser.GetEnumValue<HostingScheme>(nameof(WireMockServerSettings.HostingScheme)),
|
HostingScheme = parser.GetEnumValue<HostingScheme>(nameof(WireMockServerSettings.HostingScheme)),
|
||||||
MaxRequestLogCount = parser.GetIntValue(nameof(WireMockServerSettings.MaxRequestLogCount)),
|
MaxRequestLogCount = parser.GetIntValue(nameof(WireMockServerSettings.MaxRequestLogCount)),
|
||||||
ProtoDefinitions = parser.GetObjectValueFromJson<Dictionary<string, string[]>>(nameof(settings.ProtoDefinitions)),
|
|
||||||
QueryParameterMultipleValueSupport = parser.GetEnumValue<QueryParameterMultipleValueSupport>(nameof(WireMockServerSettings.QueryParameterMultipleValueSupport)),
|
QueryParameterMultipleValueSupport = parser.GetEnumValue<QueryParameterMultipleValueSupport>(nameof(WireMockServerSettings.QueryParameterMultipleValueSupport)),
|
||||||
ReadStaticMappings = parser.GetBoolValue(nameof(WireMockServerSettings.ReadStaticMappings)),
|
ReadStaticMappings = parser.GetBoolValue(nameof(WireMockServerSettings.ReadStaticMappings)),
|
||||||
RequestLogExpirationDuration = parser.GetIntValue(nameof(WireMockServerSettings.RequestLogExpirationDuration)),
|
RequestLogExpirationDuration = parser.GetIntValue(nameof(WireMockServerSettings.RequestLogExpirationDuration)),
|
||||||
@@ -80,6 +80,7 @@ public static class WireMockServerSettingsParser
|
|||||||
settings.AcceptAnyClientCertificate = parser.GetBoolValue(nameof(WireMockServerSettings.AcceptAnyClientCertificate));
|
settings.AcceptAnyClientCertificate = parser.GetBoolValue(nameof(WireMockServerSettings.AcceptAnyClientCertificate));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ParseJsonSerializerSettings(settings, parser);
|
||||||
ParseLoggerSettings(settings, logger, parser);
|
ParseLoggerSettings(settings, logger, parser);
|
||||||
ParsePortSettings(settings, parser);
|
ParsePortSettings(settings, parser);
|
||||||
ParseProxyAndRecordSettings(settings, parser);
|
ParseProxyAndRecordSettings(settings, parser);
|
||||||
@@ -88,6 +89,9 @@ public static class WireMockServerSettingsParser
|
|||||||
ParseActivityTracingSettings(settings, parser);
|
ParseActivityTracingSettings(settings, parser);
|
||||||
ParseWebSocketSettings(settings, parser);
|
ParseWebSocketSettings(settings, parser);
|
||||||
|
|
||||||
|
settings.GraphQLSchemas = parser.GetObjectValueFromJson<Dictionary<string, GraphQLSchemaDetails>>(nameof(settings.GraphQLSchemas), settings.DefaultJsonSerializer);
|
||||||
|
settings.ProtoDefinitions = parser.GetObjectValueFromJson<Dictionary<string, string[]>>(nameof(settings.ProtoDefinitions), settings.DefaultJsonSerializer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,4 +263,21 @@ public static class WireMockServerSettingsParser
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ParseJsonSerializerSettings(WireMockServerSettings settings, SimpleSettingsParser parser)
|
||||||
|
{
|
||||||
|
var defaultJsonSerializer = parser.GetStringValue(nameof(WireMockServerSettings.DefaultJsonSerializer));
|
||||||
|
settings.DefaultJsonSerializer = defaultJsonSerializer switch
|
||||||
|
{
|
||||||
|
nameof(SystemTextJsonConverter) => new SystemTextJsonConverter(),
|
||||||
|
_ => new NewtonsoftJsonConverter(),
|
||||||
|
};
|
||||||
|
|
||||||
|
var defaultJsonBodyTransformer = parser.GetStringValue(nameof(WireMockServerSettings.DefaultJsonBodyTransformer));
|
||||||
|
settings.DefaultJsonBodyTransformer = defaultJsonBodyTransformer switch
|
||||||
|
{
|
||||||
|
nameof(SystemTextJsonBodyTransformer) => new SystemTextJsonBodyTransformer(settings),
|
||||||
|
_ => new NewtonsoftJsonBodyTransformer(settings),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using HandlebarsDotNet;
|
using HandlebarsDotNet;
|
||||||
|
using WireMock.Transformers;
|
||||||
|
|
||||||
namespace WireMock.Transformers.Handlebars;
|
namespace WireMock.Transformers.Handlebars;
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using WireMock.Handlers;
|
|
||||||
|
|
||||||
namespace WireMock.Transformers;
|
|
||||||
|
|
||||||
internal interface ITransformerContext
|
|
||||||
{
|
|
||||||
IFileSystemHandler FileSystemHandler { get; }
|
|
||||||
|
|
||||||
string ParseAndRender(string text, object model);
|
|
||||||
|
|
||||||
object? ParseAndEvaluate(string text, object model);
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,5 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Collections;
|
|
||||||
using System.Linq;
|
|
||||||
using HandlebarsDotNet.Helpers.Models;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
@@ -14,17 +9,13 @@ namespace WireMock.Transformers;
|
|||||||
|
|
||||||
internal class Transformer : ITransformer
|
internal class Transformer : ITransformer
|
||||||
{
|
{
|
||||||
private readonly JsonSerializer _jsonSerializer;
|
private readonly IJsonBodyTransformer _jsonBodyTransformer;
|
||||||
private readonly ITransformerContextFactory _factory;
|
private readonly ITransformerContextFactory _factory;
|
||||||
|
|
||||||
public Transformer(WireMockServerSettings settings, ITransformerContextFactory factory)
|
public Transformer(WireMockServerSettings settings, ITransformerContextFactory factory)
|
||||||
{
|
{
|
||||||
_factory = Guard.NotNull(factory);
|
_factory = Guard.NotNull(factory);
|
||||||
|
_jsonBodyTransformer = Guard.NotNull(settings).DefaultJsonBodyTransformer;
|
||||||
_jsonSerializer = new JsonSerializer
|
|
||||||
{
|
|
||||||
Culture = Guard.NotNull(settings).Culture
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IBodyData? TransformBody(
|
public IBodyData? TransformBody(
|
||||||
@@ -121,13 +112,17 @@ internal class Transformer : ITransformer
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBodyData? TransformBodyData(ITransformerContext transformerContext, ReplaceNodeOptions options, TransformModel model, IBodyData original, bool useTransformerForBodyAsFile)
|
private BodyData? TransformBodyData(ITransformerContext transformerContext, ReplaceNodeOptions options, TransformModel model, IBodyData original, bool useTransformerForBodyAsFile)
|
||||||
{
|
{
|
||||||
switch (original.DetectedBodyType)
|
switch (original.DetectedBodyType)
|
||||||
{
|
{
|
||||||
case BodyType.Json:
|
case BodyType.Json:
|
||||||
case BodyType.ProtoBuf:
|
case BodyType.ProtoBuf:
|
||||||
return TransformBodyAsJson(transformerContext, options, model, original);
|
return _jsonBodyTransformer.TransformBodyAsJson(
|
||||||
|
transformerContext,
|
||||||
|
options,
|
||||||
|
model,
|
||||||
|
original);
|
||||||
|
|
||||||
case BodyType.File:
|
case BodyType.File:
|
||||||
return TransformBodyAsFile(transformerContext, model, original, useTransformerForBodyAsFile);
|
return TransformBodyAsFile(transformerContext, model, original, useTransformerForBodyAsFile);
|
||||||
@@ -159,185 +154,7 @@ internal class Transformer : ITransformer
|
|||||||
return newHeaders;
|
return newHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBodyData TransformBodyAsJson(ITransformerContext transformerContext, ReplaceNodeOptions options, object model, IBodyData original)
|
private static BodyData TransformBodyAsString(ITransformerContext transformerContext, object model, IBodyData original)
|
||||||
{
|
|
||||||
JToken? jToken = null;
|
|
||||||
switch (original.BodyAsJson)
|
|
||||||
{
|
|
||||||
case JObject bodyAsJObject:
|
|
||||||
jToken = bodyAsJObject.DeepClone();
|
|
||||||
WalkNode(transformerContext, options, jToken, model);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JArray bodyAsJArray:
|
|
||||||
jToken = bodyAsJArray.DeepClone();
|
|
||||||
WalkNode(transformerContext, options, jToken, model);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case var bodyAsEnumerable when bodyAsEnumerable is IEnumerable and not string:
|
|
||||||
jToken = JArray.FromObject(bodyAsEnumerable, _jsonSerializer);
|
|
||||||
WalkNode(transformerContext, options, jToken, model);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case string bodyAsString:
|
|
||||||
jToken = ReplaceSingleNode(transformerContext, options, bodyAsString, model);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case not null:
|
|
||||||
jToken = JObject.FromObject(original.BodyAsJson, _jsonSerializer);
|
|
||||||
WalkNode(transformerContext, options, jToken, model);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BodyData
|
|
||||||
{
|
|
||||||
Encoding = original.Encoding,
|
|
||||||
DetectedBodyType = original.DetectedBodyType,
|
|
||||||
DetectedBodyTypeFromContentType = original.DetectedBodyTypeFromContentType,
|
|
||||||
ProtoDefinition = original.ProtoDefinition,
|
|
||||||
ProtoBufMessageType = original.ProtoBufMessageType,
|
|
||||||
BodyAsJson = jToken
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private JToken ReplaceSingleNode(ITransformerContext transformerContext, ReplaceNodeOptions options, string stringValue, object model)
|
|
||||||
{
|
|
||||||
var transformedString = transformerContext.ParseAndRender(stringValue, model);
|
|
||||||
|
|
||||||
if (!string.Equals(stringValue, transformedString))
|
|
||||||
{
|
|
||||||
const string property = "_";
|
|
||||||
JObject dummy = JObject.Parse($"{{ \"{property}\": null }}");
|
|
||||||
if (dummy[property] == null)
|
|
||||||
{
|
|
||||||
// TODO: check if just returning null is fine
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
JToken node = dummy[property]!;
|
|
||||||
|
|
||||||
ReplaceNodeValue(options, node, transformedString);
|
|
||||||
|
|
||||||
return dummy[property]!;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WalkNode(ITransformerContext transformerContext, ReplaceNodeOptions options, JToken node, object model)
|
|
||||||
{
|
|
||||||
switch (node.Type)
|
|
||||||
{
|
|
||||||
case JTokenType.Object:
|
|
||||||
// In case of Object, loop all children. Do a ToArray() to avoid `Collection was modified` exceptions.
|
|
||||||
foreach (var child in node.Children<JProperty>().ToArray())
|
|
||||||
{
|
|
||||||
WalkNode(transformerContext, options, child.Value, model);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JTokenType.Array:
|
|
||||||
// In case of Array, loop all items. Do a ToArray() to avoid `Collection was modified` exceptions.
|
|
||||||
foreach (var child in node.Children().ToArray())
|
|
||||||
{
|
|
||||||
WalkNode(transformerContext, options, child, model);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JTokenType.String:
|
|
||||||
// In case of string, try to transform the value.
|
|
||||||
var stringValue = node.Value<string>();
|
|
||||||
if (string.IsNullOrEmpty(stringValue))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var transformed = transformerContext.ParseAndEvaluate(stringValue!, model);
|
|
||||||
if (!Equals(stringValue, transformed))
|
|
||||||
{
|
|
||||||
ReplaceNodeValue(options, node, transformed);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReSharper disable once UnusedParameter.Local
|
|
||||||
private void ReplaceNodeValue(ReplaceNodeOptions options, JToken node, object? transformedValue)
|
|
||||||
{
|
|
||||||
switch (transformedValue)
|
|
||||||
{
|
|
||||||
case JValue jValue:
|
|
||||||
node.Replace(jValue);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case string transformedString:
|
|
||||||
var (isConvertedFromString, convertedValueFromString) = TryConvert(options, transformedString);
|
|
||||||
if (isConvertedFromString)
|
|
||||||
{
|
|
||||||
node.Replace(JToken.FromObject(convertedValueFromString, _jsonSerializer));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node.Replace(ParseAsJObject(transformedString));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WireMockList<string> strings:
|
|
||||||
switch (strings.Count)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
node.Replace(ParseAsJObject(strings[0]));
|
|
||||||
return;
|
|
||||||
|
|
||||||
case > 1:
|
|
||||||
node.Replace(JToken.FromObject(strings.ToArray(), _jsonSerializer));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case { }:
|
|
||||||
var (isConverted, convertedValue) = TryConvert(options, transformedValue);
|
|
||||||
if (isConverted)
|
|
||||||
{
|
|
||||||
node.Replace(JToken.FromObject(convertedValue, _jsonSerializer));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
default: // It's null, skip it. Maybe remove it ?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static JToken ParseAsJObject(string stringValue)
|
|
||||||
{
|
|
||||||
return JsonUtils.TryParseAsJObject(stringValue, out var parsedAsjObject) ? parsedAsjObject : stringValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (bool IsConverted, object ConvertedValue) TryConvert(ReplaceNodeOptions options, object value)
|
|
||||||
{
|
|
||||||
var valueAsString = value as string;
|
|
||||||
|
|
||||||
if (options == ReplaceNodeOptions.Evaluate)
|
|
||||||
{
|
|
||||||
if (valueAsString != null && WrappedString.TryDecode(valueAsString, out var decoded))
|
|
||||||
{
|
|
||||||
return (true, decoded);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (false, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valueAsString != null)
|
|
||||||
{
|
|
||||||
return WrappedString.TryDecode(valueAsString, out var decoded) ?
|
|
||||||
(true, decoded) :
|
|
||||||
StringUtils.TryConvertToKnownType(valueAsString);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (false, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IBodyData TransformBodyAsString(ITransformerContext transformerContext, object model, IBodyData original)
|
|
||||||
{
|
{
|
||||||
return new BodyData
|
return new BodyData
|
||||||
{
|
{
|
||||||
@@ -348,7 +165,7 @@ internal class Transformer : ITransformer
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IBodyData TransformBodyAsFile(ITransformerContext transformerContext, object model, IBodyData original, bool useTransformerForBodyAsFile)
|
private static BodyData TransformBodyAsFile(ITransformerContext transformerContext, object model, IBodyData original, bool useTransformerForBodyAsFile)
|
||||||
{
|
{
|
||||||
var transformedBodyAsFilename = transformerContext.ParseAndRender(original.BodyAsFile!, model);
|
var transformedBodyAsFilename = transformerContext.ParseAndRender(original.BodyAsFile!, model);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>Minimal version from the lightweight Http Mocking Server for .NET</Description>
|
<Description>Minimal version from the lightweight Http Mocking Server for .NET</Description>
|
||||||
<AssemblyTitle>WireMock.Net.Minimal</AssemblyTitle>
|
<AssemblyTitle>WireMock.Net.Minimal</AssemblyTitle>
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
|
||||||
<PackageReference Include="TinyMapper.Signed" Version="4.0.0" />
|
<PackageReference Include="TinyMapper.Signed" Version="4.0.0" />
|
||||||
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="6.34.0" />
|
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="6.34.0" />
|
||||||
<PackageReference Include="Scriban.Signed" Version="7.0.6" />
|
<PackageReference Include="Scriban.Signed" Version="7.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>Some extensions for NUnit</Description>
|
<Description>Some extensions for NUnit</Description>
|
||||||
<AssemblyTitle>WireMock.Net.NUnit</AssemblyTitle>
|
<AssemblyTitle>WireMock.Net.NUnit</AssemblyTitle>
|
||||||
@@ -25,9 +25,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.9.0" />
|
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.13.0" />
|
||||||
<PackageReference Include="NUnit" Version="4.4.0" />
|
<PackageReference Include="NUnit" Version="4.4.0" />
|
||||||
<PackageReference Include="Stef.Validation" Version="0.2.0" />
|
<PackageReference Include="Stef.Validation" Version="0.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
<PackageReference Include="RamlToOpenApiConverter.SourceOnly" Version="0.11.0" />
|
<PackageReference Include="RamlToOpenApiConverter.SourceOnly" Version="0.11.0" />
|
||||||
<PackageReference Include="YamlDotNet" Version="16.3.0" />
|
<PackageReference Include="YamlDotNet" Version="16.3.0" />
|
||||||
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.19.1" />
|
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.19.1" />
|
||||||
<PackageReference Include="Stef.Validation" Version="0.2.0" />
|
<PackageReference Include="Stef.Validation" Version="0.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
|
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
|
||||||
|
|||||||
+41
-12
@@ -32,15 +32,15 @@ public partial class WireMockAdminApiAssertions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CustomAssertion]
|
[CustomAssertion]
|
||||||
public AndConstraint<WireMockAdminApiAssertions> WithBodyAsJson(object body, string because = "", params object[] becauseArgs)
|
public AndConstraint<WireMockAdminApiAssertions> WithBodyAsJson(object body, IJsonMatcher? jsonMatcher = null, string because = "", params object[] becauseArgs)
|
||||||
{
|
{
|
||||||
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
|
return WithBodyAsJson(jsonMatcher ?? new JsonMatcher(body), because, becauseArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomAssertion]
|
[CustomAssertion]
|
||||||
public AndConstraint<WireMockAdminApiAssertions> WithBodyAsJson(string body, string because = "", params object[] becauseArgs)
|
public AndConstraint<WireMockAdminApiAssertions> WithBodyAsJson(string body, IJsonMatcher? jsonMatcher = null, string because = "", params object[] becauseArgs)
|
||||||
{
|
{
|
||||||
return WithBodyAsJson(new JsonMatcher(body), because, becauseArgs);
|
return WithBodyAsJson(jsonMatcher ?? new JsonMatcher(body), because, becauseArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomAssertion]
|
[CustomAssertion]
|
||||||
@@ -127,15 +127,44 @@ public partial class WireMockAdminApiAssertions
|
|||||||
|
|
||||||
private static string? FormatBody(object? body)
|
private static string? FormatBody(object? body)
|
||||||
{
|
{
|
||||||
return body switch
|
if (body == null)
|
||||||
{
|
{
|
||||||
null => null,
|
return null;
|
||||||
string str => str,
|
}
|
||||||
AnyOf<string, StringPattern>[] stringPatterns => FormatBodies(stringPatterns.Select(p => p.GetPattern())),
|
|
||||||
byte[] bytes => $"byte[{bytes.Length}] {{...}}",
|
if (body is string str)
|
||||||
JToken jToken => jToken.ToString(Formatting.None),
|
{
|
||||||
_ => JToken.FromObject(body).ToString(Formatting.None)
|
return str;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (body is AnyOf<string, StringPattern>[] stringPatterns)
|
||||||
|
{
|
||||||
|
return FormatBodies(stringPatterns.Select(p => p.GetPattern()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body is byte[] bytes)
|
||||||
|
{
|
||||||
|
return $"byte[{bytes.Length}] {{...}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body is JToken jToken)
|
||||||
|
{
|
||||||
|
return jToken.ToString(Formatting.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.IO.FileNotFoundException : Could not load file or assembly 'System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
|
||||||
|
var typeName = body.GetType().FullName;
|
||||||
|
if (typeName == "System.Text.Json.JsonElement")
|
||||||
|
{
|
||||||
|
return ((dynamic)body).GetRawText();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName == "System.Text.Json.JsonDocument")
|
||||||
|
{
|
||||||
|
return ((dynamic)body).RootElement.GetRawText();
|
||||||
|
}
|
||||||
|
|
||||||
|
return JToken.FromObject(body).ToString(Formatting.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? FormatBodies(IEnumerable<object?> bodies)
|
private static string? FormatBodies(IEnumerable<object?> bodies)
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ public static class WireMockAdminApiExtensions
|
|||||||
waitTime = (int)(InitialWaitingTimeInMilliSeconds * Math.Pow(2, retries));
|
waitTime = (int)(InitialWaitingTimeInMilliSeconds * Math.Pow(2, retries));
|
||||||
await Task.Delay(waitTime, cancellationToken);
|
await Task.Delay(waitTime, cancellationToken);
|
||||||
isHealthy = await IsHealthyAsync(adminApi, cancellationToken);
|
isHealthy = await IsHealthyAsync(adminApi, cancellationToken);
|
||||||
|
|
||||||
retries++;
|
retries++;
|
||||||
totalWaitTime += waitTime;
|
totalWaitTime += waitTime;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.9.0" />
|
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.13.0" />
|
||||||
<PackageReference Include="RestEase" Version="1.6.4" />
|
<PackageReference Include="RestEase" Version="1.6.4" />
|
||||||
<PackageReference Include="Stef.Validation" Version="0.2.0" />
|
<PackageReference Include="Stef.Validation" Version="0.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IJsonPathMatcher
|
||||||
|
/// <seealso cref="IStringMatcher"/> and <seealso cref="IObjectMatcher"/>.
|
||||||
|
/// </summary>
|
||||||
|
public interface IJsonPathMatcher : IStringMatcher, IObjectMatcher
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ISystemTextJsonPathMatcher
|
||||||
|
/// <seealso cref="IJsonPathMatcher"/>.
|
||||||
|
/// </summary>
|
||||||
|
public interface ISystemTextJsonPathMatcher : IJsonPathMatcher
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -7,9 +7,10 @@ using System.Runtime.CompilerServices;
|
|||||||
[assembly: InternalsVisibleTo("WireMock.Net.GraphQL, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
[assembly: InternalsVisibleTo("WireMock.Net.GraphQL, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
[assembly: InternalsVisibleTo("WireMock.Net.ProtoBuf, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
[assembly: InternalsVisibleTo("WireMock.Net.ProtoBuf, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
[assembly: InternalsVisibleTo("WireMock.Net.Matchers.CSharpCode, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
[assembly: InternalsVisibleTo("WireMock.Net.Matchers.CSharpCode, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
|
[assembly: InternalsVisibleTo("WireMock.Net.Matchers.SystemTextJsonPath, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
[assembly: InternalsVisibleTo("WireMock.Net.OpenTelemetry, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
[assembly: InternalsVisibleTo("WireMock.Net.OpenTelemetry, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
// [assembly: InternalsVisibleTo("WireMock.Net.StandAlone, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
// [assembly: InternalsVisibleTo("WireMock.Net.StandAlone, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
|
|
||||||
// Needed for Moq in the UnitTest project
|
// Needed for Moq in the UnitTest project
|
||||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
|
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using JsonConverter.Abstractions;
|
using JsonConverter.Abstractions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
|
|
||||||
@@ -19,8 +17,10 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder
|
|||||||
/// <param name="body">The body.</param>
|
/// <param name="body">The body.</param>
|
||||||
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
|
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
|
||||||
/// <param name="encoding">The body encoding.</param>
|
/// <param name="encoding">The body encoding.</param>
|
||||||
|
/// <param name="jsonConverter">The JSON converter.</param>
|
||||||
|
/// <param name="options">The JSON converter options.</param>
|
||||||
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
|
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
|
||||||
IResponseBuilder WithBody(string body, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null);
|
IResponseBuilder WithBody(string body, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null, IJsonConverter? jsonConverter = null, JsonConverterOptions? options = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WithBody : Create a ... response based on a callback function.
|
/// WithBody : Create a ... response based on a callback function.
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ internal static class JsonSerializationConstants
|
|||||||
IgnoreNullValues = true
|
IgnoreNullValues = true
|
||||||
};
|
};
|
||||||
|
|
||||||
//internal static readonly JsonSerializerSettings JsonSerializerSettingsDefault = new()
|
internal static readonly JsonConverterOptions JsonConverterOptionsIncludeNullValues = new()
|
||||||
//{
|
|
||||||
// Formatting = Formatting.Indented,
|
|
||||||
// NullValueHandling = NullValueHandling.Ignore
|
|
||||||
//};
|
|
||||||
|
|
||||||
internal static readonly JsonSerializerSettings JsonSerializerSettingsIncludeNullValues = new()
|
|
||||||
{
|
{
|
||||||
Formatting = Formatting.Indented,
|
WriteIndented = true,
|
||||||
NullValueHandling = NullValueHandling.Include
|
IgnoreNullValues = false
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static readonly JsonConverterOptions JsonConverterOptionsWithDateParsingNone = new()
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DateParseHandling = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static readonly JsonSerializerSettings JsonDeserializerSettingsWithDateParsingNone = new()
|
internal static readonly JsonSerializerSettings JsonDeserializerSettingsWithDateParsingNone = new()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using JsonConverter.Abstractions;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
@@ -191,9 +192,9 @@ internal class SimpleSettingsParser
|
|||||||
return GetValue(name, values => values.FirstOrDefault());
|
return GetValue(name, values => values.FirstOrDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
public T? GetObjectValueFromJson<T>(string name)
|
public T? GetObjectValueFromJson<T>(string name, IJsonConverter jsonConverter)
|
||||||
{
|
{
|
||||||
var value = GetValue(name, values => values.FirstOrDefault());
|
var value = GetValue(name, values => values.FirstOrDefault());
|
||||||
return string.IsNullOrWhiteSpace(value) ? default : JsonUtils.DeserializeObject<T>(value!);
|
return string.IsNullOrWhiteSpace(value) ? default : jsonConverter.Deserialize<T>(value!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using WireMock.Logging;
|
|||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.RegularExpressions;
|
using WireMock.RegularExpressions;
|
||||||
|
using WireMock.Transformers;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
|
|
||||||
namespace WireMock.Settings;
|
namespace WireMock.Settings;
|
||||||
@@ -304,12 +305,6 @@ public class WireMockServerSettings
|
|||||||
[PublicAPI, JsonIgnore]
|
[PublicAPI, JsonIgnore]
|
||||||
public IDictionary<string, Func<MatcherModel, IMatcher>>? CustomMatcherMappings { get; set; }
|
public IDictionary<string, Func<MatcherModel, IMatcher>>? CustomMatcherMappings { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="JsonSerializerSettings"/> used when the JSON response is generated.
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI, JsonIgnore]
|
|
||||||
public JsonSerializerSettings? JsonSerializerSettings { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Culture to use.
|
/// The Culture to use.
|
||||||
/// Currently used for:
|
/// Currently used for:
|
||||||
@@ -362,11 +357,32 @@ public class WireMockServerSettings
|
|||||||
/// Default is <see cref="NewtonsoftJsonConverter"/>.
|
/// Default is <see cref="NewtonsoftJsonConverter"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IJsonConverter DefaultJsonSerializer { get; set; } = new NewtonsoftJsonConverter();
|
[JsonConverter(typeof(WireMockSettingsJsonConverter))]
|
||||||
|
public IJsonConverter DefaultJsonSerializer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default JSON body transformer used for template-based JSON body transformations.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Set this property to provide a custom implementation for transforming JSON and ProtoBuf body content.
|
||||||
|
/// Default is <see cref="NewtonsoftJsonBodyTransformer"/>.
|
||||||
|
/// </remarks>
|
||||||
|
[PublicAPI]
|
||||||
|
[JsonConverter(typeof(WireMockSettingsJsonConverter))]
|
||||||
|
public IJsonBodyTransformer DefaultJsonBodyTransformer { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WebSocket settings.
|
/// WebSocket settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public WebSocketSettings? WebSocketSettings { get; set; }
|
public WebSocketSettings? WebSocketSettings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WireMockServerSettings"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public WireMockServerSettings()
|
||||||
|
{
|
||||||
|
DefaultJsonSerializer = new NewtonsoftJsonConverter();
|
||||||
|
DefaultJsonBodyTransformer = new NewtonsoftJsonBodyTransformer(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Reflection;
|
||||||
|
using JsonConverter.Abstractions;
|
||||||
|
using JsonConverter.Newtonsoft.Json;
|
||||||
|
using JsonConverter.System.Text.Json;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using WireMock.Transformers;
|
||||||
|
using NewtonsoftJsonConverterBase = Newtonsoft.Json.JsonConverter;
|
||||||
|
|
||||||
|
namespace WireMock.Settings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WireMockSettingsJsonConverter serializes and deserializes the special interface-based settings properties as type names.
|
||||||
|
/// </summary>
|
||||||
|
public class WireMockSettingsJsonConverter : NewtonsoftJsonConverterBase
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return typeof(IJsonConverter).IsAssignableFrom(objectType) || typeof(IJsonBodyTransformer).IsAssignableFrom(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
writer.WriteValue(value?.GetType().FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonToken.Null)
|
||||||
|
{
|
||||||
|
return existingValue ?? CreateDefaultValue(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.TokenType != JsonToken.String)
|
||||||
|
{
|
||||||
|
reader.Skip();
|
||||||
|
return existingValue ?? CreateDefaultValue(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeName = reader.Value as string;
|
||||||
|
|
||||||
|
if (typeof(IJsonConverter).IsAssignableFrom(objectType))
|
||||||
|
{
|
||||||
|
return CreateJsonConverter(typeName) ?? existingValue ?? new NewtonsoftJsonConverter();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(IJsonBodyTransformer).IsAssignableFrom(objectType))
|
||||||
|
{
|
||||||
|
var settings = ExtractSettings(existingValue as IJsonBodyTransformer);
|
||||||
|
return settings != null
|
||||||
|
? CreateJsonBodyTransformer(typeName, settings) ?? existingValue ?? new NewtonsoftJsonBodyTransformer(settings)
|
||||||
|
: existingValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object? CreateDefaultValue(Type objectType)
|
||||||
|
{
|
||||||
|
if (typeof(IJsonConverter).IsAssignableFrom(objectType))
|
||||||
|
{
|
||||||
|
return new NewtonsoftJsonConverter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IJsonConverter? CreateJsonConverter(string? typeName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(typeName))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName == nameof(NewtonsoftJsonConverter) || typeName == typeof(NewtonsoftJsonConverter).FullName)
|
||||||
|
{
|
||||||
|
return new NewtonsoftJsonConverter();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName == nameof(SystemTextJsonConverter) || typeName == typeof(SystemTextJsonConverter).FullName)
|
||||||
|
{
|
||||||
|
return new SystemTextJsonConverter();
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = GetType(typeName);
|
||||||
|
if (type == null || !typeof(IJsonConverter).IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Activator.CreateInstance(type) as IJsonConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IJsonBodyTransformer? CreateJsonBodyTransformer(string? typeName, WireMockServerSettings settings)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(typeName))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName == nameof(NewtonsoftJsonBodyTransformer) || typeName == typeof(NewtonsoftJsonBodyTransformer).FullName)
|
||||||
|
{
|
||||||
|
return new NewtonsoftJsonBodyTransformer(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeName == nameof(SystemTextJsonBodyTransformer) || typeName == typeof(SystemTextJsonBodyTransformer).FullName)
|
||||||
|
{
|
||||||
|
return new SystemTextJsonBodyTransformer(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = GetType(typeName);
|
||||||
|
if (type == null || !typeof(IJsonBodyTransformer).IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var constructorWithSettings = type.GetConstructor([typeof(WireMockServerSettings)]);
|
||||||
|
if (constructorWithSettings != null)
|
||||||
|
{
|
||||||
|
return constructorWithSettings.Invoke([settings]) as IJsonBodyTransformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Activator.CreateInstance(type) as IJsonBodyTransformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static WireMockServerSettings? ExtractSettings(IJsonBodyTransformer? existingValue)
|
||||||
|
{
|
||||||
|
if (existingValue == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingValue.GetType()
|
||||||
|
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||||
|
.Where(field => typeof(WireMockServerSettings).IsAssignableFrom(field.FieldType))
|
||||||
|
.Select(field => field.GetValue(existingValue) as WireMockServerSettings)
|
||||||
|
.FirstOrDefault(settings => settings != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Type? GetType(string typeName)
|
||||||
|
{
|
||||||
|
return Type.GetType(typeName, throwOnError: false) ??
|
||||||
|
AppDomain.CurrentDomain.GetAssemblies()
|
||||||
|
.Select(assembly => assembly.GetType(typeName, throwOnError: false))
|
||||||
|
.FirstOrDefault(foundType => foundType != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using WireMock.Types;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Transformers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the contract for transforming JSON-like body data using a transformer context.
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public interface IJsonBodyTransformer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms the JSON body using the provided transformer context and model.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="transformerContext">The transformer context used to render and evaluate template values.</param>
|
||||||
|
/// <param name="options">The JSON node replacement behavior to apply during transformation.</param>
|
||||||
|
/// <param name="model">The model used when rendering or evaluating template values.</param>
|
||||||
|
/// <param name="original">The original body data to transform.</param>
|
||||||
|
/// <returns>The transformed JSON body data.</returns>
|
||||||
|
BodyData TransformBodyAsJson(
|
||||||
|
ITransformerContext transformerContext,
|
||||||
|
ReplaceNodeOptions options,
|
||||||
|
object model,
|
||||||
|
IBodyData original);
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using WireMock.Handlers;
|
||||||
|
|
||||||
|
namespace WireMock.Transformers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the transformer context used to render and evaluate templates during response transformation.
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public interface ITransformerContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the file system handler used by the current transformer context.
|
||||||
|
/// </summary>
|
||||||
|
IFileSystemHandler FileSystemHandler { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renders the specified template text using the supplied model.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The template text to render.</param>
|
||||||
|
/// <param name="model">The model used during rendering.</param>
|
||||||
|
/// <returns>The rendered text.</returns>
|
||||||
|
string ParseAndRender(string text, object model);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates the specified template text using the supplied model.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The template text to evaluate.</param>
|
||||||
|
/// <param name="model">The model used during evaluation.</param>
|
||||||
|
/// <returns>The evaluated value.</returns>
|
||||||
|
object? ParseAndEvaluate(string text, object model);
|
||||||
|
}
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using HandlebarsDotNet.Helpers.Models;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using JsonConverter.Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using WireMock.Settings;
|
||||||
|
using WireMock.Types;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Transformers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default JSON body transformer implementation based on Newtonsoft.Json.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="NewtonsoftJsonBodyTransformer"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="settings">The server settings used to configure JSON transformation behavior.</param>
|
||||||
|
[PublicAPI]
|
||||||
|
public class NewtonsoftJsonBodyTransformer(WireMockServerSettings settings) : IJsonBodyTransformer
|
||||||
|
{
|
||||||
|
private static readonly NewtonsoftJsonConverter _jsonConverter = new();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public BodyData TransformBodyAsJson(
|
||||||
|
ITransformerContext transformerContext,
|
||||||
|
ReplaceNodeOptions options,
|
||||||
|
object model,
|
||||||
|
IBodyData original)
|
||||||
|
{
|
||||||
|
var jsonSerializer = new JsonSerializer
|
||||||
|
{
|
||||||
|
Culture = settings.Culture
|
||||||
|
};
|
||||||
|
|
||||||
|
JToken? jToken = null;
|
||||||
|
switch (original.BodyAsJson)
|
||||||
|
{
|
||||||
|
case JObject bodyAsJObject:
|
||||||
|
jToken = bodyAsJObject.DeepClone();
|
||||||
|
WalkNode(transformerContext, jsonSerializer, options, jToken, model);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JArray bodyAsJArray:
|
||||||
|
jToken = bodyAsJArray.DeepClone();
|
||||||
|
WalkNode(transformerContext, jsonSerializer, options, jToken, model);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case var bodyAsEnumerable when bodyAsEnumerable is IEnumerable and not string:
|
||||||
|
jToken = JArray.FromObject(bodyAsEnumerable, jsonSerializer);
|
||||||
|
WalkNode(transformerContext, jsonSerializer, options, jToken, model);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case string bodyAsString:
|
||||||
|
jToken = ReplaceSingleNode(transformerContext, jsonSerializer, options, bodyAsString, model);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case not null:
|
||||||
|
jToken = JObject.FromObject(original.BodyAsJson, jsonSerializer);
|
||||||
|
WalkNode(transformerContext, jsonSerializer, options, jToken, model);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BodyData
|
||||||
|
{
|
||||||
|
Encoding = original.Encoding,
|
||||||
|
DetectedBodyType = original.DetectedBodyType,
|
||||||
|
DetectedBodyTypeFromContentType = original.DetectedBodyTypeFromContentType,
|
||||||
|
ProtoDefinition = original.ProtoDefinition,
|
||||||
|
ProtoBufMessageType = original.ProtoBufMessageType,
|
||||||
|
BodyAsJson = jToken
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private JToken ParseAsJObject(string stringValue)
|
||||||
|
{
|
||||||
|
if (_jsonConverter.IsValidJson(stringValue))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Try to convert this string into a JObject
|
||||||
|
return JObject.Parse(stringValue!);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
settings.Logger.Warn("Failed to parse string ''{0}'' as JSON. Returning the original string value.", stringValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JToken ReplaceSingleNode(ITransformerContext transformerContext, JsonSerializer jsonSerializer, ReplaceNodeOptions options, string stringValue, object model)
|
||||||
|
{
|
||||||
|
var transformedString = transformerContext.ParseAndRender(stringValue, model);
|
||||||
|
|
||||||
|
if (!string.Equals(stringValue, transformedString))
|
||||||
|
{
|
||||||
|
const string property = "_";
|
||||||
|
JObject dummy = JObject.Parse($"{{ \"{property}\": null }}");
|
||||||
|
if (dummy[property] == null)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
JToken node = dummy[property]!;
|
||||||
|
|
||||||
|
ReplaceNodeValue(jsonSerializer, options, node, transformedString);
|
||||||
|
|
||||||
|
return dummy[property]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WalkNode(ITransformerContext transformerContext, JsonSerializer jsonSerializer, ReplaceNodeOptions options, JToken node, object model)
|
||||||
|
{
|
||||||
|
switch (node.Type)
|
||||||
|
{
|
||||||
|
case JTokenType.Object:
|
||||||
|
foreach (var child in node.Children<JProperty>().ToArray())
|
||||||
|
{
|
||||||
|
WalkNode(transformerContext, jsonSerializer, options, child.Value, model);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.Array:
|
||||||
|
foreach (var child in node.Children().ToArray())
|
||||||
|
{
|
||||||
|
WalkNode(transformerContext, jsonSerializer, options, child, model);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JTokenType.String:
|
||||||
|
var stringValue = node.Value<string>();
|
||||||
|
if (string.IsNullOrEmpty(stringValue))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var transformed = transformerContext.ParseAndEvaluate(stringValue!, model);
|
||||||
|
if (!Equals(stringValue, transformed))
|
||||||
|
{
|
||||||
|
ReplaceNodeValue(jsonSerializer, options, node, transformed);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReplaceNodeValue(JsonSerializer jsonSerializer, ReplaceNodeOptions options, JToken node, object? transformedValue)
|
||||||
|
{
|
||||||
|
switch (transformedValue)
|
||||||
|
{
|
||||||
|
case JValue jValue:
|
||||||
|
node.Replace(jValue);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case string transformedString:
|
||||||
|
var (isConvertedFromString, convertedValueFromString) = TryConvert(options, transformedString);
|
||||||
|
if (isConvertedFromString)
|
||||||
|
{
|
||||||
|
node.Replace(JToken.FromObject(convertedValueFromString, jsonSerializer));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node.Replace(ParseAsJObject(transformedString));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WireMockList<string> strings:
|
||||||
|
switch (strings.Count)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
node.Replace(ParseAsJObject(strings[0]));
|
||||||
|
return;
|
||||||
|
|
||||||
|
case > 1:
|
||||||
|
node.Replace(JToken.FromObject(strings.ToArray(), jsonSerializer));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case { }:
|
||||||
|
var (isConverted, convertedValue) = TryConvert(options, transformedValue);
|
||||||
|
if (isConverted)
|
||||||
|
{
|
||||||
|
node.Replace(JToken.FromObject(convertedValue, jsonSerializer));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (bool IsConverted, object ConvertedValue) TryConvert(ReplaceNodeOptions options, object value)
|
||||||
|
{
|
||||||
|
var valueAsString = value as string;
|
||||||
|
|
||||||
|
if (options == ReplaceNodeOptions.Evaluate)
|
||||||
|
{
|
||||||
|
if (valueAsString != null && WrappedString.TryDecode(valueAsString, out var decoded))
|
||||||
|
{
|
||||||
|
return (true, decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueAsString != null)
|
||||||
|
{
|
||||||
|
return WrappedString.TryDecode(valueAsString, out var decoded)
|
||||||
|
? (true, decoded)
|
||||||
|
: TryConvertToKnownType(valueAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static (bool IsConverted, object ConvertedValue) TryConvertToKnownType(string value)
|
||||||
|
{
|
||||||
|
if (bool.TryParse(value, out var boolResult))
|
||||||
|
{
|
||||||
|
return (true, boolResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (int.TryParse(value, out var intResult))
|
||||||
|
{
|
||||||
|
return (true, intResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (long.TryParse(value, out var longResult))
|
||||||
|
{
|
||||||
|
return (true, longResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (double.TryParse(value, out var doubleResult))
|
||||||
|
{
|
||||||
|
return (true, doubleResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Guid.TryParseExact(value, "D", out var guidResult))
|
||||||
|
{
|
||||||
|
return (true, guidResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TimeSpan.TryParse(value, out var timeSpanResult))
|
||||||
|
{
|
||||||
|
return (true, timeSpanResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DateTime.TryParse(value, out var dateTimeResult))
|
||||||
|
{
|
||||||
|
return (true, dateTimeResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((value.StartsWith("ftp://", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
value.StartsWith("ftps://", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
value.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
value.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) &&
|
||||||
|
Uri.TryCreate(value, UriKind.RelativeOrAbsolute, out var uriResult))
|
||||||
|
{
|
||||||
|
return (true, uriResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using HandlebarsDotNet.Helpers.Models;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using JsonConverter.System.Text.Json;
|
||||||
|
using WireMock.Settings;
|
||||||
|
using WireMock.Types;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Transformers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JSON body transformer implementation based on System.Text.Json.
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public class SystemTextJsonBodyTransformer(WireMockServerSettings settings) : IJsonBodyTransformer
|
||||||
|
{
|
||||||
|
private static readonly SystemTextJsonConverter _jsonConverter = new();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public BodyData TransformBodyAsJson(
|
||||||
|
ITransformerContext transformerContext,
|
||||||
|
ReplaceNodeOptions options,
|
||||||
|
object model,
|
||||||
|
IBodyData original)
|
||||||
|
{
|
||||||
|
JsonNode? jsonNode = null;
|
||||||
|
switch (original.BodyAsJson)
|
||||||
|
{
|
||||||
|
case JsonObject bodyAsJsonObject:
|
||||||
|
jsonNode = CloneNode(bodyAsJsonObject);
|
||||||
|
jsonNode = WalkNode(transformerContext, options, jsonNode, model);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonArray bodyAsJsonArray:
|
||||||
|
jsonNode = CloneNode(bodyAsJsonArray);
|
||||||
|
jsonNode = WalkNode(transformerContext, options, jsonNode, model);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case var bodyAsEnumerable when bodyAsEnumerable is IEnumerable and not string:
|
||||||
|
jsonNode = JsonSerializer.SerializeToNode(bodyAsEnumerable);
|
||||||
|
if (jsonNode != null)
|
||||||
|
{
|
||||||
|
jsonNode = WalkNode(transformerContext, options, jsonNode, model);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case string bodyAsString:
|
||||||
|
jsonNode = ReplaceSingleNode(transformerContext, options, bodyAsString, model);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case not null:
|
||||||
|
jsonNode = JsonSerializer.SerializeToNode(original.BodyAsJson);
|
||||||
|
if (jsonNode != null)
|
||||||
|
{
|
||||||
|
jsonNode = WalkNode(transformerContext, options, jsonNode, model);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BodyData
|
||||||
|
{
|
||||||
|
Encoding = original.Encoding,
|
||||||
|
DetectedBodyType = original.DetectedBodyType,
|
||||||
|
DetectedBodyTypeFromContentType = original.DetectedBodyTypeFromContentType,
|
||||||
|
ProtoDefinition = original.ProtoDefinition,
|
||||||
|
ProtoBufMessageType = original.ProtoBufMessageType,
|
||||||
|
BodyAsJson = jsonNode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonNode ParseAsJsonObject(string stringValue)
|
||||||
|
{
|
||||||
|
if (_jsonConverter.IsValidJson(stringValue))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var parsed = JsonNode.Parse(stringValue);
|
||||||
|
if (parsed is JsonObject)
|
||||||
|
{
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
settings.Logger.Warn("Failed to parse string ''{0}'' as JSON. Returning the original string value.", stringValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonValue.Create(stringValue)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonNode? ReplaceSingleNode(ITransformerContext transformerContext, ReplaceNodeOptions options, string stringValue, object model)
|
||||||
|
{
|
||||||
|
var transformedString = transformerContext.ParseAndRender(stringValue, model);
|
||||||
|
|
||||||
|
if (!string.Equals(stringValue, transformedString))
|
||||||
|
{
|
||||||
|
return ReplaceNodeValue(options, transformedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonValue.Create(stringValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonNode? WalkNode(ITransformerContext transformerContext, ReplaceNodeOptions options, JsonNode? node, object model)
|
||||||
|
{
|
||||||
|
switch (node)
|
||||||
|
{
|
||||||
|
case JsonObject jsonObject:
|
||||||
|
foreach (var property in jsonObject.ToArray())
|
||||||
|
{
|
||||||
|
jsonObject[property.Key] = WalkNode(transformerContext, options, property.Value, model);
|
||||||
|
}
|
||||||
|
return jsonObject;
|
||||||
|
|
||||||
|
case JsonArray jsonArray:
|
||||||
|
for (var i = 0; i < jsonArray.Count; i++)
|
||||||
|
{
|
||||||
|
jsonArray[i] = WalkNode(transformerContext, options, jsonArray[i], model);
|
||||||
|
}
|
||||||
|
return jsonArray;
|
||||||
|
|
||||||
|
case JsonValue jsonValue when jsonValue.TryGetValue<string>(out var stringValue):
|
||||||
|
if (string.IsNullOrEmpty(stringValue))
|
||||||
|
{
|
||||||
|
return jsonValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var transformed = transformerContext.ParseAndEvaluate(stringValue!, model);
|
||||||
|
return !Equals(stringValue, transformed) ? ReplaceNodeValue(options, transformed) ?? jsonValue : jsonValue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonNode? ReplaceNodeValue(ReplaceNodeOptions options, object? transformedValue)
|
||||||
|
{
|
||||||
|
switch (transformedValue)
|
||||||
|
{
|
||||||
|
case JsonNode jsonNode:
|
||||||
|
return CloneNode(jsonNode);
|
||||||
|
|
||||||
|
case string transformedString:
|
||||||
|
var (isConvertedFromString, convertedValueFromString) = TryConvert(options, transformedString);
|
||||||
|
return isConvertedFromString
|
||||||
|
? JsonSerializer.SerializeToNode(convertedValueFromString)
|
||||||
|
: ParseAsJsonObject(transformedString);
|
||||||
|
|
||||||
|
case WireMockList<string> strings:
|
||||||
|
switch (strings.Count)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return ParseAsJsonObject(strings[0]);
|
||||||
|
|
||||||
|
case > 1:
|
||||||
|
return JsonSerializer.SerializeToNode(strings.ToArray());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case { }:
|
||||||
|
var (isConverted, convertedValue) = TryConvert(options, transformedValue);
|
||||||
|
if (isConverted)
|
||||||
|
{
|
||||||
|
return JsonSerializer.SerializeToNode(convertedValue);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JsonNode? CloneNode(JsonNode? node)
|
||||||
|
{
|
||||||
|
#if NET8_0_OR_GREATER
|
||||||
|
return node?.DeepClone();
|
||||||
|
#else
|
||||||
|
return node == null ? null : JsonNode.Parse(node.ToJsonString());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (bool IsConverted, object ConvertedValue) TryConvert(ReplaceNodeOptions options, object value)
|
||||||
|
{
|
||||||
|
var valueAsString = value as string;
|
||||||
|
|
||||||
|
if (options == ReplaceNodeOptions.Evaluate)
|
||||||
|
{
|
||||||
|
if (valueAsString != null && WrappedString.TryDecode(valueAsString, out var decoded))
|
||||||
|
{
|
||||||
|
return (true, decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueAsString != null)
|
||||||
|
{
|
||||||
|
return WrappedString.TryDecode(valueAsString, out var decoded)
|
||||||
|
? (true, decoded)
|
||||||
|
: NewtonsoftJsonBodyTransformer.TryConvertToKnownType(valueAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Constants;
|
using WireMock.Constants;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
|
using WireMock.Serialization;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
|
|
||||||
namespace WireMock.Util;
|
namespace WireMock.Util;
|
||||||
@@ -26,7 +26,7 @@ internal static class BodyParser
|
|||||||
CONNECT - No defined body semantics
|
CONNECT - No defined body semantics
|
||||||
PATCH - Body supported.
|
PATCH - Body supported.
|
||||||
*/
|
*/
|
||||||
private static readonly IDictionary<string, bool> BodyAllowedForMethods = new Dictionary<string, bool>
|
private static readonly Dictionary<string, bool> BodyAllowedForMethods = new()
|
||||||
{
|
{
|
||||||
{ HttpRequestMethod.HEAD, false },
|
{ HttpRequestMethod.HEAD, false },
|
||||||
{ HttpRequestMethod.GET, false },
|
{ HttpRequestMethod.GET, false },
|
||||||
@@ -129,11 +129,11 @@ internal static class BodyParser
|
|||||||
{
|
{
|
||||||
Guard.NotNull(settings);
|
Guard.NotNull(settings);
|
||||||
|
|
||||||
var bodyWithContentEncoding = await ReadBytesAsync(settings.Stream, settings.ContentEncoding, settings.DecompressGZipAndDeflate).ConfigureAwait(false);
|
var (ContentType, Bytes) = await ReadBytesAsync(settings.Stream, settings.ContentEncoding, settings.DecompressGZipAndDeflate).ConfigureAwait(false);
|
||||||
var data = new BodyData
|
var data = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsBytes = bodyWithContentEncoding.Bytes,
|
BodyAsBytes = Bytes,
|
||||||
DetectedCompression = bodyWithContentEncoding.ContentType,
|
DetectedCompression = ContentType,
|
||||||
DetectedBodyType = BodyType.Bytes,
|
DetectedBodyType = BodyType.Bytes,
|
||||||
DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(settings.ContentType)
|
DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(settings.ContentType)
|
||||||
};
|
};
|
||||||
@@ -169,17 +169,17 @@ internal static class BodyParser
|
|||||||
data.DetectedBodyType = BodyType.FormUrlEncoded;
|
data.DetectedBodyType = BodyType.FormUrlEncoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If string is not null or empty, try to deserialize the string to a JObject
|
// If string is not null or empty, try to deserialize the string
|
||||||
if (settings.DeserializeJson && JsonUtils.IsJson(data.BodyAsString))
|
if (settings.DeserializeJson && settings.DefaultJsonConverter.IsValidJson(data.BodyAsString))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
data.BodyAsJson = JsonUtils.DeserializeObject(data.BodyAsString);
|
data.BodyAsJson = settings.DefaultJsonConverter.Deserialize<object>(data.BodyAsString, JsonSerializationConstants.JsonConverterOptionsWithDateParsingNone);
|
||||||
data.DetectedBodyType = BodyType.Json;
|
data.DetectedBodyType = BodyType.Json;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// JsonConvert failed, just ignore.
|
// JsonConverter failed, just ignore.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +202,7 @@ internal static class BodyParser
|
|||||||
return (null, data);
|
return (null, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsProbablyText(byte[] data)
|
private static bool IsProbablyText(byte[] data)
|
||||||
{
|
{
|
||||||
if (data.Length == 0)
|
if (data.Length == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.IO;
|
using JsonConverter.Abstractions;
|
||||||
|
using JsonConverter.Newtonsoft.Json;
|
||||||
|
|
||||||
namespace WireMock.Util;
|
namespace WireMock.Util;
|
||||||
|
|
||||||
@@ -35,4 +36,13 @@ internal class BodyParserSettings
|
|||||||
/// Try to deserialize the body as FormUrlEncoded.
|
/// Try to deserialize the body as FormUrlEncoded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DeserializeFormUrlEncoded { get; set; } = true;
|
public bool DeserializeFormUrlEncoded { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default JSON converter used for deserialization.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Set this property to customize how objects are serialized to and deserialized from JSON during mapping.
|
||||||
|
/// Default is <see cref="NewtonsoftJsonConverter"/>.
|
||||||
|
/// </remarks>
|
||||||
|
public IJsonConverter DefaultJsonConverter { get; set; } = new NewtonsoftJsonConverter();
|
||||||
}
|
}
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Text;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using WireMock.Serialization;
|
|
||||||
|
|
||||||
namespace WireMock.Util;
|
|
||||||
|
|
||||||
internal static class JsonUtils
|
|
||||||
{
|
|
||||||
public static bool IsJson(string? value)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(value))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = value!.Trim();
|
|
||||||
|
|
||||||
return (value.StartsWith("{") && value.EndsWith("}")) || (value.StartsWith("[") && value.EndsWith("]"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryParseAsJObject(string? strInput, [NotNullWhen(true)] out JObject? value)
|
|
||||||
{
|
|
||||||
value = null;
|
|
||||||
|
|
||||||
if (!IsJson(strInput))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Try to convert this string into a JToken
|
|
||||||
value = JObject.Parse(strInput!);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Serialize(object value)
|
|
||||||
{
|
|
||||||
return JsonConvert.SerializeObject(value, JsonSerializationConstants.JsonSerializerSettingsIncludeNullValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] SerializeAsPactFile(object value)
|
|
||||||
{
|
|
||||||
var json = JsonConvert.SerializeObject(value, JsonSerializationConstants.JsonSerializerSettingsPact);
|
|
||||||
return Encoding.UTF8.GetBytes(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Load a Newtonsoft.Json.Linq.JObject from a string that contains JSON.
|
|
||||||
/// Using : DateParseHandling = DateParseHandling.None
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="json">A System.String that contains JSON.</param>
|
|
||||||
/// <returns>A Newtonsoft.Json.Linq.JToken populated from the string that contains JSON.</returns>
|
|
||||||
public static JToken Parse(string json)
|
|
||||||
{
|
|
||||||
return JsonConvert.DeserializeObject<JToken>(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserializes the JSON to a .NET object.
|
|
||||||
/// Using : DateParseHandling = DateParseHandling.None
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="json">A System.String that contains JSON.</param>
|
|
||||||
/// <returns>The deserialized object from the JSON string.</returns>
|
|
||||||
public static object DeserializeObject(string json)
|
|
||||||
{
|
|
||||||
return JsonConvert.DeserializeObject(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserializes the JSON to the specified .NET type.
|
|
||||||
/// Using : DateParseHandling = DateParseHandling.None
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="json">A System.String that contains JSON.</param>
|
|
||||||
/// <returns>The deserialized object from the JSON string.</returns>
|
|
||||||
public static T DeserializeObject<T>(string json)
|
|
||||||
{
|
|
||||||
return JsonConvert.DeserializeObject<T>(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T? TryDeserializeObject<T>(string json)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return JsonConvert.DeserializeObject<T>(json);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T ParseJTokenToObject<T>(object? value)
|
|
||||||
{
|
|
||||||
if (value != null && value.GetType() == typeof(T))
|
|
||||||
{
|
|
||||||
return (T)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value switch
|
|
||||||
{
|
|
||||||
JToken tokenValue => tokenValue.ToObject<T>()!,
|
|
||||||
|
|
||||||
_ => throw new NotSupportedException($"Unable to convert value to {typeof(T)}.")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JToken ConvertValueToJToken(object value)
|
|
||||||
{
|
|
||||||
// Check if JToken, string, IEnumerable or object
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case JToken tokenValue:
|
|
||||||
return tokenValue;
|
|
||||||
|
|
||||||
case string stringValue:
|
|
||||||
return Parse(stringValue);
|
|
||||||
|
|
||||||
case IEnumerable enumerableValue:
|
|
||||||
return JArray.FromObject(enumerableValue);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return JObject.FromObject(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
|
|
||||||
|
|||||||
@@ -27,21 +27,22 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.9" />
|
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.9" />
|
||||||
<PackageReference Include="Stef.Validation" Version="0.2.0" />
|
<PackageReference Include="Stef.Validation" Version="0.3.0" />
|
||||||
<PackageReference Include="AnyOf" Version="0.5.0.1" />
|
<PackageReference Include="AnyOf" Version="0.5.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
||||||
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.9.0" />
|
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.13.0" />
|
||||||
|
<PackageReference Include="JsonConverter.System.Text.Json" Version="0.13.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Handlebars.Net.Helpers" Version="2.5.2" />
|
<PackageReference Include="Handlebars.Net.Helpers" Version="2.5.5" />
|
||||||
<!--<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.5.2" />-->
|
<!--<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.5.2" />-->
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.5.2" />
|
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.5.5" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.5.2" />
|
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.5.5" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.5.2" />
|
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.5.5" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.5.2" />
|
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.5.5" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.5.2" />
|
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.5.5" />
|
||||||
<PackageReference Include="Handlebars.Net.Helpers.Xslt" Version="2.5.2" />
|
<PackageReference Include="Handlebars.Net.Helpers.Xslt" Version="2.5.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
<PackageReference Include="Stef.Validation" Version="0.2.0" />
|
<PackageReference Include="Stef.Validation" Version="0.3.0" />
|
||||||
<PackageReference Include="TUnit.Core" Version="1.17.29" />
|
<PackageReference Include="TUnit.Core" Version="1.17.29" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ public static class TestcontainersUtils
|
|||||||
throw new InvalidOperationException($"The {nameof(TestcontainersSettings.OS.DockerEndpointAuthConfig)} is null. Check if Docker is started.");
|
throw new InvalidOperationException($"The {nameof(TestcontainersSettings.OS.DockerEndpointAuthConfig)} is null. Check if Docker is started.");
|
||||||
}
|
}
|
||||||
|
|
||||||
using var dockerClientConfig = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration();
|
var dockerClientBuilder = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientBuilder();
|
||||||
using var dockerClient = dockerClientConfig.CreateClient();
|
using var dockerClient = dockerClientBuilder.Build();
|
||||||
|
|
||||||
var version = await dockerClient.System.GetVersionAsync();
|
var version = await dockerClient.System.GetVersionAsync();
|
||||||
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
|
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0 ? OSPlatform.Windows : OSPlatform.Linux;
|
||||||
|
|||||||
@@ -38,8 +38,8 @@
|
|||||||
<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="Stef.Validation" Version="0.2.0" />
|
<PackageReference Include="Stef.Validation" Version="0.3.0" />
|
||||||
<PackageReference Include="Testcontainers" Version="4.10.0" />
|
<PackageReference Include="Testcontainers" Version="4.12.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
<PackageReference Include="Stef.Validation" Version="0.2.0" />
|
<PackageReference Include="Stef.Validation" Version="0.3.0" />
|
||||||
<PackageReference Include="xunit.v3.extensibility.core" Version="3.2.2" />
|
<PackageReference Include="xunit.v3.extensibility.core" Version="3.2.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
<PackageReference Include="Stef.Validation" Version="0.2.0" />
|
<PackageReference Include="Stef.Validation" Version="0.3.0" />
|
||||||
<PackageReference Include="xUnit.abstractions" Version="2.0.3" />
|
<PackageReference Include="xUnit.abstractions" Version="2.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -34,5 +34,6 @@
|
|||||||
<ProjectReference Include="../WireMock.Net.GraphQL/WireMock.Net.GraphQL.csproj" />
|
<ProjectReference Include="../WireMock.Net.GraphQL/WireMock.Net.GraphQL.csproj" />
|
||||||
<ProjectReference Include="../WireMock.Net.ProtoBuf/WireMock.Net.ProtoBuf.csproj" />
|
<ProjectReference Include="../WireMock.Net.ProtoBuf/WireMock.Net.ProtoBuf.csproj" />
|
||||||
<ProjectReference Include="../WireMock.Net.OpenTelemetry/WireMock.Net.OpenTelemetry.csproj" />
|
<ProjectReference Include="../WireMock.Net.OpenTelemetry/WireMock.Net.OpenTelemetry.csproj" />
|
||||||
|
<ProjectReference Include="../WireMock.Net.Matchers.SystemTextJsonPath/WireMock.Net.Matchers.SystemTextJsonPath.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
using WireMock.Net.StandAlone;
|
using WireMock.Net.StandAlone;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Sdk Name="Aspire.AppHost.Sdk" Version="13.1.0" />
|
<Sdk Name="Aspire.AppHost.Sdk" Version="13.4.0" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
@@ -19,7 +19,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting.AppHost" Version="13.1.1" />
|
<PackageReference Include="Aspire.Hosting.AppHost" Version="13.4.3" />
|
||||||
|
|
||||||
|
<!-- CVE-2026-48109 -->
|
||||||
|
<PackageReference Include="MessagePack" Version="2.5.302" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting.Testing" Version="13.1.1" />
|
<PackageReference Include="Aspire.Hosting.Testing" Version="13.4.3" />
|
||||||
<PackageReference Include="Codecov" Version="1.13.0" />
|
<PackageReference Include="Codecov" Version="1.13.0" />
|
||||||
<PackageReference Include="coverlet.msbuild" Version="6.0.4">
|
<PackageReference Include="coverlet.msbuild" Version="6.0.4">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
@@ -25,13 +25,16 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
|
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
|
||||||
<PackageReference Include="Moq" Version="4.20.72" />
|
<PackageReference Include="Moq" Version="4.20.72" />
|
||||||
<PackageReference Include="xunit.v3" Version="3.2.2" />
|
<PackageReference Include="xunit.v3" Version="3.2.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
|
<!-- CVE-2026-48109 -->
|
||||||
|
<PackageReference Include="MessagePack" Version="2.5.302" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -92,17 +92,11 @@ public class WireMockServerBuilderExtensionsTests
|
|||||||
Tag = "latest"
|
Tag = "latest"
|
||||||
});
|
});
|
||||||
|
|
||||||
var endpointAnnotation = wiremock.Resource.Annotations.OfType<EndpointAnnotation>().FirstOrDefault();
|
var endpointAnnotation = wiremock.Resource.Annotations.OfType<EndpointAnnotation>().First();
|
||||||
endpointAnnotation.Should().BeEquivalentTo(new EndpointAnnotation(
|
endpointAnnotation.Protocol.Should().Be(ProtocolType.Tcp);
|
||||||
protocol: ProtocolType.Tcp,
|
endpointAnnotation.UriScheme.Should().Be("http");
|
||||||
uriScheme: "http",
|
endpointAnnotation.Port.Should().Be(port);
|
||||||
transport: null,
|
endpointAnnotation.TargetPort.Should().Be(80);
|
||||||
name: null,
|
|
||||||
port: port,
|
|
||||||
targetPort: 80,
|
|
||||||
isExternal: null,
|
|
||||||
isProxied: true
|
|
||||||
));
|
|
||||||
|
|
||||||
wiremock.Resource.Annotations.OfType<EnvironmentCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
|
wiremock.Resource.Annotations.OfType<EnvironmentCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
|
||||||
wiremock.Resource.Annotations.OfType<CommandLineArgsCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
|
wiremock.Resource.Annotations.OfType<CommandLineArgsCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
|
||||||
@@ -153,39 +147,24 @@ public class WireMockServerBuilderExtensionsTests
|
|||||||
endpointAnnotations.Should().HaveCount(3);
|
endpointAnnotations.Should().HaveCount(3);
|
||||||
|
|
||||||
var endpointAnnotationForHttp80 = endpointAnnotations[0];
|
var endpointAnnotationForHttp80 = endpointAnnotations[0];
|
||||||
endpointAnnotationForHttp80.Should().BeEquivalentTo(new EndpointAnnotation(
|
endpointAnnotationForHttp80.Protocol.Should().Be(ProtocolType.Tcp);
|
||||||
protocol: ProtocolType.Tcp,
|
endpointAnnotationForHttp80.UriScheme.Should().Be("http");
|
||||||
uriScheme: "http",
|
endpointAnnotationForHttp80.Port.Should().BeNull();
|
||||||
transport: null,
|
endpointAnnotationForHttp80.TargetPort.Should().Be(80);
|
||||||
name: null,
|
|
||||||
port: null,
|
|
||||||
targetPort: 80,
|
|
||||||
isExternal: null,
|
|
||||||
isProxied: true
|
|
||||||
));
|
|
||||||
var endpointAnnotationForHttpFreePort = endpointAnnotations[1];
|
var endpointAnnotationForHttpFreePort = endpointAnnotations[1];
|
||||||
endpointAnnotationForHttpFreePort.Should().BeEquivalentTo(new EndpointAnnotation(
|
endpointAnnotationForHttpFreePort.Protocol.Should().Be(ProtocolType.Tcp);
|
||||||
protocol: ProtocolType.Tcp,
|
endpointAnnotationForHttpFreePort.UriScheme.Should().Be("http");
|
||||||
uriScheme: "http",
|
endpointAnnotationForHttpFreePort.Name.Should().Be($"http-{freePorts[0]}");
|
||||||
transport: null,
|
endpointAnnotationForHttpFreePort.Port.Should().Be(freePorts[0]);
|
||||||
name: $"http-{freePorts[0]}",
|
endpointAnnotationForHttpFreePort.TargetPort.Should().Be(freePorts[0]);
|
||||||
port: freePorts[0],
|
|
||||||
targetPort: freePorts[0],
|
|
||||||
isExternal: null,
|
|
||||||
isProxied: true
|
|
||||||
));
|
|
||||||
|
|
||||||
var endpointAnnotationForGrpcFreePort = endpointAnnotations[2];
|
var endpointAnnotationForGrpcFreePort = endpointAnnotations[2];
|
||||||
endpointAnnotationForGrpcFreePort.Should().BeEquivalentTo(new EndpointAnnotation(
|
endpointAnnotationForGrpcFreePort.Protocol.Should().Be(ProtocolType.Tcp);
|
||||||
protocol: ProtocolType.Tcp,
|
endpointAnnotationForGrpcFreePort.UriScheme.Should().Be("grpc");
|
||||||
uriScheme: "grpc",
|
endpointAnnotationForGrpcFreePort.Name.Should().Be($"grpc-{freePorts[1]}");
|
||||||
transport: null,
|
endpointAnnotationForGrpcFreePort.Port.Should().Be(freePorts[1]);
|
||||||
name: $"grpc-{freePorts[1]}",
|
endpointAnnotationForGrpcFreePort.TargetPort.Should().Be(freePorts[1]);
|
||||||
port: freePorts[1],
|
|
||||||
targetPort: freePorts[1],
|
|
||||||
isExternal: null,
|
|
||||||
isProxied: true
|
|
||||||
));
|
|
||||||
|
|
||||||
wiremock.Resource.Annotations.OfType<EnvironmentCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
|
wiremock.Resource.Annotations.OfType<EnvironmentCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
|
||||||
wiremock.Resource.Annotations.OfType<CommandLineArgsCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
|
wiremock.Resource.Annotations.OfType<CommandLineArgsCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
|
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
|
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
|
||||||
<PackageReference Include="Moq" Version="4.20.72" />
|
<PackageReference Include="Moq" Version="4.20.72" />
|
||||||
<PackageReference Include="xunit.v3" Version="3.2.2" />
|
<PackageReference Include="xunit.v3" Version="3.2.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
|
|||||||
@@ -11,12 +11,12 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
|
<PackageReference Include="AwesomeAssertions" Version="9.4.0" />
|
||||||
<PackageReference Include="coverlet.collector" Version="8.0.1">
|
<PackageReference Include="coverlet.collector" Version="10.0.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="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
|
||||||
<PackageReference Include="WireMock.Net" Version="2.1.0" />
|
<PackageReference Include="WireMock.Net" Version="2.10.0" />
|
||||||
<PackageReference Include="xunit.v3" Version="3.2.2" />
|
<PackageReference Include="xunit.v3" Version="3.2.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
@@ -30,6 +30,12 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Update="JetBrains.Annotations" Version="2025.2.4" />
|
<PackageReference Update="JetBrains.Annotations" Version="2025.2.4" />
|
||||||
|
<PackageReference Include="OpenTelemetry" Version="1.15.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Api" Version="1.15.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Api.ProviderBuilderExtensions" Version="1.15.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
|
||||||
<PackageReference Update="SonarAnalyzer.CSharp" Version="10.11.0.117924" />
|
<PackageReference Update="SonarAnalyzer.CSharp" Version="10.11.0.117924" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -523,4 +523,151 @@ public class JsonMatcherTests
|
|||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(1.0, score);
|
Assert.Equal(1.0, score);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
[Fact]
|
||||||
|
public void JsonMatcher_IsMatch_Array_WithIgnoreArrayOrderTrue_DifferentOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new JsonMatcher(new[] { "a", "b", "c" }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jArray = new JArray
|
||||||
|
{
|
||||||
|
"c",
|
||||||
|
"a",
|
||||||
|
"b"
|
||||||
|
};
|
||||||
|
var score = matcher.IsMatch(jArray).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void JsonMatcher_IsMatch_Array_WithIgnoreArrayOrderFalse_DifferentOrder_ShouldNotMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new JsonMatcher(new[] { "a", "b", "c" }, ignoreArrayOrder: false);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jArray = new JArray
|
||||||
|
{
|
||||||
|
"c",
|
||||||
|
"a",
|
||||||
|
"b"
|
||||||
|
};
|
||||||
|
var score = matcher.IsMatch(jArray).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(MatchScores.Mismatch, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void JsonMatcher_IsMatch_Array_WithIgnoreArrayOrderTrue_SameOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new JsonMatcher(new[] { "a", "b", "c" }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jArray = new JArray
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
"b",
|
||||||
|
"c"
|
||||||
|
};
|
||||||
|
var score = matcher.IsMatch(jArray).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void JsonMatcher_IsMatch_Array_WithIgnoreArrayOrderTrue_DifferentLength_ShouldNotMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new JsonMatcher(new[] { "a", "b", "c" }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jArray = new JArray
|
||||||
|
{
|
||||||
|
"a",
|
||||||
|
"b"
|
||||||
|
};
|
||||||
|
var score = matcher.IsMatch(jArray).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(MatchScores.Mismatch, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void JsonMatcher_IsMatch_ObjectWithArray_WithIgnoreArrayOrderTrue_DifferentOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new JsonMatcher(new { Items = new[] { "x", "y", "z" } }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jObject = new JObject
|
||||||
|
{
|
||||||
|
{ "Items", new JArray("z", "x", "y") }
|
||||||
|
};
|
||||||
|
var score = matcher.IsMatch(jObject).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void JsonMatcher_IsMatch_ArrayAsString_WithIgnoreArrayOrderTrue_DifferentOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new JsonMatcher("[ \"a\", \"b\", \"c\" ]", ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jArray = new JArray
|
||||||
|
{
|
||||||
|
"c",
|
||||||
|
"b",
|
||||||
|
"a"
|
||||||
|
};
|
||||||
|
var score = matcher.IsMatch(jArray).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void JsonMatcher_IsMatch_ArrayOfNumbers_WithIgnoreArrayOrderTrue_DifferentOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new JsonMatcher(new[] { 1, 2, 3 }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jArray = new JArray
|
||||||
|
{
|
||||||
|
3,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
};
|
||||||
|
var score = matcher.IsMatch(jArray).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(MatchBehaviour.AcceptOnMatch, false, false, false)]
|
||||||
|
[InlineData(MatchBehaviour.AcceptOnMatch, true, false, true)]
|
||||||
|
[InlineData(MatchBehaviour.RejectOnMatch, true, true, false)]
|
||||||
|
public void JsonMatcher_GetCSharpCodeArguments_ShouldIncludeAllConstructorArguments(MatchBehaviour matchBehaviour, bool ignoreCase, bool regex, bool ignoreArrayOrder)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new JsonMatcher(matchBehaviour, "{ \"id\": 1 }", ignoreCase, regex, ignoreArrayOrder);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = matcher.GetCSharpCodeArguments();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().StartWith($"new JsonMatcher(WireMock.Matchers.MatchBehaviour.{matchBehaviour},");
|
||||||
|
result.Should().EndWith($", {ignoreCase.ToString().ToLowerInvariant()}, {regex.ToString().ToLowerInvariant()}, {ignoreArrayOrder.ToString().ToLowerInvariant()})");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -416,4 +416,20 @@ public class JsonPartialWildcardMatcherTests
|
|||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(1.0, match);
|
Assert.Equal(1.0, match);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
[Fact]
|
||||||
|
public void JsonPartialWildcardMatcher_IsMatch_WithRegexTrue_DateFormat_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new JsonPartialWildcardMatcher(
|
||||||
|
new { date = "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$", id = 1 },
|
||||||
|
ignoreCase: false,
|
||||||
|
regex: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{\"date\":\"2026-06-09T22:23:18.53421+00:00\",\"id\":1}").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,484 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.Matchers;
|
||||||
|
|
||||||
|
public class SystemTextJsonMatcherTests
|
||||||
|
{
|
||||||
|
public enum NormalEnumStj
|
||||||
|
{
|
||||||
|
Abc
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Test1Stj
|
||||||
|
{
|
||||||
|
public NormalEnumStj NormalEnum { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_GetName()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var name = matcher.Name;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
name.Should().Be("SystemTextJsonMatcher");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_GetValue()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var value = matcher.Value;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
value.Should().Be("{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_WithInvalidStringValue_Should_ThrowException()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
Action action = () => new SystemTextJsonMatcher(MatchBehaviour.AcceptOnMatch, "{ \"Id\"");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
action.Should().Throw<JsonException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_WithInvalidObjectValue_Should_ThrowException()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
Action action = () => new SystemTextJsonMatcher(MatchBehaviour.AcceptOnMatch, new MemoryStream());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
action.Should().Throw<Exception>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_WithInvalidValue_Should_ReturnMismatch_And_Exception_ShouldBeSet()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher("{}");
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = matcher.IsMatch(stream);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Score.Should().Be(MatchScores.Mismatch);
|
||||||
|
result.Exception.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_ByteArray()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var bytes = new byte[0];
|
||||||
|
var matcher = new SystemTextJsonMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(bytes).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_NullString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string? s = null;
|
||||||
|
var matcher = new SystemTextJsonMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(s).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_NullObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
object? o = null;
|
||||||
|
var matcher = new SystemTextJsonMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(o).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_JsonArrayAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher("[ \"x\", \"y\" ]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("[ \"x\", \"y\" ]").RootElement;
|
||||||
|
var match = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_JsonObjectAsString_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher("{ \"Id\" : 1, \"Name\" : \"Test\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }").RootElement;
|
||||||
|
var match = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_AnonymousObject_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new { Id = 1, Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_AnonymousObject_ShouldNotMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new { Id = 1, Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\", \"Other\" : \"abc\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(MatchScores.Mismatch, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_WithIgnoreCaseTrue_JsonObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new { id = 1, Name = "test" }, true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"NaMe\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_WithIgnoreCaseTrue_JsonObjectParsed()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new { Id = 1, Name = "TESt" }, true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_JsonObjectAsString_RejectOnMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(MatchBehaviour.RejectOnMatch, "{ \"Id\" : 1, \"Name\" : \"Test\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_JsonObjectWithDateTimeOffsetAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher("{ \"preferredAt\" : \"2019-11-21T10:32:53.2210009+00:00\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"preferredAt\" : \"2019-11-21T10:32:53.2210009+00:00\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_NormalEnum()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new Test1Stj { NormalEnum = NormalEnumStj.Abc });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"NormalEnum\" : 0 }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_WithRegexTrue_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new { Id = "^\\d+$", Name = "Test" }, regex: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : \"42\", \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_WithRegexTrue_Complex_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new
|
||||||
|
{
|
||||||
|
Complex = new
|
||||||
|
{
|
||||||
|
Id = "^\\d+$",
|
||||||
|
Name = ".*"
|
||||||
|
}
|
||||||
|
}, regex: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Complex\" : { \"Id\" : \"42\", \"Name\" : \"Test\" } }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_WithRegexTrue_Complex_ShouldNotMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new
|
||||||
|
{
|
||||||
|
Complex = new
|
||||||
|
{
|
||||||
|
Id = "^\\d+$",
|
||||||
|
Name = ".*"
|
||||||
|
}
|
||||||
|
}, regex: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Complex\" : { \"Id\" : \"42\", \"Name\" : \"Test\", \"Other\" : \"Other\" } }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(MatchScores.Mismatch, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_WithRegexTrue_Array_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new
|
||||||
|
{
|
||||||
|
Array = new[] { "^\\d+$", ".*" }
|
||||||
|
}, regex: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Array\" : [ \"42\", \"test\" ] }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_WithRegexTrue_Array_ShouldNotMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new
|
||||||
|
{
|
||||||
|
Array = new[] { "^\\d+$", ".*" }
|
||||||
|
}, regex: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Array\" : [ \"42\", \"test\", \"other\" ] }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(MatchScores.Mismatch, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_GuidAndString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var id = Guid.NewGuid();
|
||||||
|
var idAsString = id.ToString();
|
||||||
|
var matcher = new SystemTextJsonMatcher(new { Id = id });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch($"{{ \"Id\" : \"{idAsString}\" }}").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_StringAndGuid()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var id = Guid.NewGuid();
|
||||||
|
var idAsString = id.ToString();
|
||||||
|
var matcher = new SystemTextJsonMatcher(new { Id = idAsString });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch($"{{ \"Id\" : \"{id}\" }}").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_JsonElement_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new { Id = 1, Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }").RootElement;
|
||||||
|
var match = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_Array_WithIgnoreArrayOrderTrue_DifferentOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new[] { "a", "b", "c" }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("[ \"c\", \"a\", \"b\" ]").RootElement;
|
||||||
|
var score = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_Array_WithIgnoreArrayOrderFalse_DifferentOrder_ShouldNotMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new[] { "a", "b", "c" }, ignoreArrayOrder: false);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("[ \"c\", \"a\", \"b\" ]").RootElement;
|
||||||
|
var score = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(MatchScores.Mismatch, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_Array_WithIgnoreArrayOrderTrue_SameOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new[] { "a", "b", "c" }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("[ \"a\", \"b\", \"c\" ]").RootElement;
|
||||||
|
var score = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_Array_WithIgnoreArrayOrderTrue_DifferentLength_ShouldNotMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new[] { "a", "b", "c" }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("[ \"a\", \"b\" ]").RootElement;
|
||||||
|
var score = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(MatchScores.Mismatch, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_ObjectWithArray_WithIgnoreArrayOrderTrue_DifferentOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new { Items = new[] { "x", "y", "z" } }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Items\" : [ \"z\", \"x\", \"y\" ] }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_ArrayAsString_WithIgnoreArrayOrderTrue_DifferentOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher("[ \"a\", \"b\", \"c\" ]", ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("[ \"c\", \"b\", \"a\" ]").RootElement;
|
||||||
|
var score = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonMatcher_IsMatch_ArrayOfNumbers_WithIgnoreArrayOrderTrue_DifferentOrder_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(new[] { 1, 2, 3 }, ignoreArrayOrder: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("[ 3, 1, 2 ]").RootElement;
|
||||||
|
var score = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(MatchBehaviour.AcceptOnMatch, false, false, false)]
|
||||||
|
[InlineData(MatchBehaviour.AcceptOnMatch, true, false, true)]
|
||||||
|
[InlineData(MatchBehaviour.RejectOnMatch, true, true, false)]
|
||||||
|
public void SystemTextJsonMatcher_GetCSharpCodeArguments_ShouldIncludeAllConstructorArguments(MatchBehaviour matchBehaviour, bool ignoreCase, bool regex, bool ignoreArrayOrder)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonMatcher(matchBehaviour, "{ \"id\": 1 }", ignoreCase, regex, ignoreArrayOrder);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = matcher.GetCSharpCodeArguments();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().StartWith($"new SystemTextJsonMatcher(WireMock.Matchers.MatchBehaviour.{matchBehaviour},");
|
||||||
|
result.Should().EndWith($", {ignoreCase.ToString().ToLowerInvariant()}, {regex.ToString().ToLowerInvariant()}, {ignoreArrayOrder.ToString().ToLowerInvariant()})");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,411 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.Matchers;
|
||||||
|
|
||||||
|
public class SystemTextJsonPartialMatcherTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_GetName()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string name = matcher.Name;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
name.Should().Be("SystemTextJsonPartialMatcher");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_GetValue()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
object value = matcher.Value;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
value.Should().Be("{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_WithInvalidStringValue_Should_ThrowException()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
Action action = () => new SystemTextJsonPartialMatcher(MatchBehaviour.AcceptOnMatch, "{ \"Id\"");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
action.Should().Throw<JsonException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_WithInvalidObjectValue_Should_ThrowException()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
Action action = () => new SystemTextJsonPartialMatcher(MatchBehaviour.AcceptOnMatch, new MemoryStream());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
action.Should().Throw<Exception>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_WithInvalidValue_Should_ReturnMismatch_And_Exception_ShouldBeSet()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{}");
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = matcher.IsMatch(stream);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Score.Should().Be(MatchScores.Mismatch);
|
||||||
|
result.Exception.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_ByteArray()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var bytes = new byte[0];
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(bytes).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_NullString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string? s = null;
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(s).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_NullObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
object? o = null;
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(o).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_JsonArray()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new[] { "x", "y" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("[ \"x\", \"y\" ]").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_JsonObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new { Id = 1, Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_WithRegexTrue()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new { Id = "^\\d+$", Name = "Test" }, false, true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"Id\" : \"1\", \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_WithRegexFalse()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new { Id = "^\\d+$", Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_GuidAsString_UsingRegex()
|
||||||
|
{
|
||||||
|
var guid = new Guid("1111238e-b775-44a9-a263-95e570135c94");
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Name = "^1111[a-fA-F0-9]{4}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"
|
||||||
|
}, false, true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch($"{{ \"Id\" : 1, \"Name\" : \"{guid}\" }}").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_WithIgnoreCaseTrue_JsonObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new { id = 1, Name = "test" }, true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"Id\" : 1, \"NaMe\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_JsonObjectParsed()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new { Id = 1, Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_WithIgnoreCaseTrue_JsonObjectParsed()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new { Id = 1, Name = "TESt" }, true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_JsonArrayAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("[ \"x\", \"y\" ]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("[ \"x\", \"y\" ]").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_JsonObjectAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{ \"Id\" : 1, \"Name\" : \"Test\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_JsonObjectAsStringWithDottedPropertyName()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{ \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\" : \"Test\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_GuidAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var guid = Guid.NewGuid();
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new { Id = 1, Name = guid });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch($"{{ \"Id\" : 1, \"Name\" : \"{guid}\" }}").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_WithIgnoreCaseTrue_JsonObjectAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{ \"Id\" : 1, \"Name\" : \"test\" }", true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_JsonObjectAsString_RejectOnMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(MatchBehaviour.RejectOnMatch, "{ \"Id\" : 1, \"Name\" : \"Test\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_JsonObjectWithDateTimeOffsetAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher("{ \"preferredAt\" : \"2019-11-21T10:32:53.2210009+00:00\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("{ \"preferredAt\" : \"2019-11-21T10:32:53.2210009+00:00\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("{\"test\":\"abc\"}", "{\"test\":\"abc\",\"other\":\"xyz\"}")]
|
||||||
|
[InlineData("\"test\"", "\"test\"")]
|
||||||
|
[InlineData("123", "123")]
|
||||||
|
[InlineData("[\"test\"]", "[\"test\"]")]
|
||||||
|
[InlineData("[\"test\"]", "[\"test\", \"other\"]")]
|
||||||
|
[InlineData("[123]", "[123]")]
|
||||||
|
[InlineData("[123]", "[123, 456]")]
|
||||||
|
[InlineData("{ \"test\":\"value\" }", "{\"test\":\"value\",\"other\":123}")]
|
||||||
|
[InlineData("{ \"test\":\"value\" }", "{\"test\":\"value\"}")]
|
||||||
|
[InlineData("{\"test\":{\"nested\":\"value\"}}", "{\"test\":{\"nested\":\"value\"}}")]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_StringInputValidMatch(string value, string input)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(input).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("\"test\"", null)]
|
||||||
|
[InlineData("\"test1\"", "\"test2\"")]
|
||||||
|
[InlineData("123", "1234")]
|
||||||
|
[InlineData("[\"test\"]", "[\"test1\"]")]
|
||||||
|
[InlineData("[\"test\"]", "[\"test1\", \"test2\"]")]
|
||||||
|
[InlineData("[123]", "[1234]")]
|
||||||
|
[InlineData("{}", "\"test\"")]
|
||||||
|
[InlineData("{ \"test\":\"value\" }", "{\"test\":\"value2\"}")]
|
||||||
|
[InlineData("{ \"test.nested\":\"value\" }", "{\"test\":{\"nested\":\"value1\"}}")]
|
||||||
|
[InlineData("{\"test\":{\"test1\":\"value\"}}", "{\"test\":{\"test1\":\"value1\"}}")]
|
||||||
|
[InlineData("[{ \"test.nested\":\"value\" }]", "[{\"test\":{\"nested\":\"value1\"}}]")]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_StringInputWithInvalidMatch(string value, string? input)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(input).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("{ \"test.nested\":123 }", "{\"test\":{\"nested\":123}}")]
|
||||||
|
[InlineData("{ \"test.nested\":[123, 456] }", "{\"test\":{\"nested\":[123, 456]}}")]
|
||||||
|
[InlineData("{ \"test.nested\":\"value\" }", "{\"test\":{\"nested\":\"value\"}}")]
|
||||||
|
[InlineData("{ \"['name.with.dot']\":\"value\" }", "{\"name.with.dot\":\"value\"}")]
|
||||||
|
[InlineData("[{ \"test.nested\":\"value\" }]", "[{\"test\":{\"nested\":\"value\"}}]")]
|
||||||
|
[InlineData("[{ \"['name.with.dot']\":\"value\" }]", "[{\"name.with.dot\":\"value\"}]")]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_ValueAsPathValidMatch(string value, string input)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(input).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("{ \"test.nested\":123 }", "{\"test\":{\"nested\":456}}")]
|
||||||
|
[InlineData("{ \"test.nested\":[123, 456] }", "{\"test\":{\"nested\":[1, 2]}}")]
|
||||||
|
[InlineData("{ \"test.nested\":\"value\" }", "{\"test\":{\"nested\":\"value1\"}}")]
|
||||||
|
[InlineData("{ \"['name.with.dot']\":\"value\" }", "{\"name.with.dot\":\"value1\"}")]
|
||||||
|
[InlineData("[{ \"test.nested\":\"value\" }]", "[{\"test\":{\"nested\":\"value1\"}}]")]
|
||||||
|
[InlineData("[{ \"['name.with.dot']\":\"value\" }]", "[{\"name.with.dot\":\"value1\"}]")]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_ValueAsPathInvalidMatch(string value, string input)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(input).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialMatcher_IsMatch_JsonElement_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialMatcher(new { Id = 1, Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("{ \"Id\" : 1, \"Name\" : \"Test\", \"Extra\" : \"value\" }").RootElement;
|
||||||
|
double match = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,398 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.Matchers;
|
||||||
|
|
||||||
|
public class SystemTextJsonPartialWildcardMatcherTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_GetName()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var name = matcher.Name;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
name.Should().Be("SystemTextJsonPartialWildcardMatcher");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_GetValue()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var value = matcher.Value;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
value.Should().Be("{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_WithInvalidStringValue_Should_ThrowException()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
Action action = () => new SystemTextJsonPartialWildcardMatcher(MatchBehaviour.AcceptOnMatch, "{ \"Id\"");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
action.Should().Throw<JsonException>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_WithInvalidObjectValue_Should_ThrowException()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
Action action = () => new SystemTextJsonPartialWildcardMatcher(MatchBehaviour.AcceptOnMatch, new MemoryStream());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
action.Should().Throw<Exception>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_WithInvalidValue_Should_ReturnMismatch_And_Exception_ShouldBeSet()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
var result = matcher.IsMatch(stream);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Score.Should().Be(MatchScores.Mismatch);
|
||||||
|
result.Exception.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_ByteArray()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var bytes = new byte[0];
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(bytes).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_NullString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
string? s = null;
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(s).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_NullObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
object? o = null;
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("{}");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(o).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_JsonArray()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(new[] { "x", "y" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("[ \"x\", \"y\" ]").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_JsonObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(new { Id = 1, Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_WithIgnoreCaseTrue_JsonObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(new { id = 1, Name = "test" }, true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"NaMe\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_JsonObjectParsed()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(new { Id = 1, Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_WithIgnoreCaseTrue_JsonObjectParsed()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(new { Id = 1, Name = "TESt" }, true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_JsonArrayAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("[ \"x\", \"y\" ]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("[ \"x\", \"y\" ]").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_JsonObjectAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("{ \"Id\" : 1, \"Name\" : \"Test\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_WithIgnoreCaseTrue_JsonObjectAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("{ \"Id\" : 1, \"Name\" : \"test\" }", true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_JsonObjectAsString_RejectOnMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(MatchBehaviour.RejectOnMatch, "{ \"Id\" : 1, \"Name\" : \"Test\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Name\" : \"Test\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_JsonObjectWithDateTimeOffsetAsString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher("{ \"preferredAt\" : \"2019-11-21T10:32:53.2210009+00:00\" }");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"preferredAt\" : \"2019-11-21T10:32:53.2210009+00:00\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("{\"test\":\"abc\"}", "{\"test\":\"abc\",\"other\":\"xyz\"}")]
|
||||||
|
[InlineData("\"test\"", "\"test\"")]
|
||||||
|
[InlineData("123", "123")]
|
||||||
|
[InlineData("[\"test\"]", "[\"test\"]")]
|
||||||
|
[InlineData("[\"test\"]", "[\"test\", \"other\"]")]
|
||||||
|
[InlineData("[123]", "[123]")]
|
||||||
|
[InlineData("[123]", "[123, 456]")]
|
||||||
|
[InlineData("{ \"test\":\"value\" }", "{\"test\":\"value\",\"other\":123}")]
|
||||||
|
[InlineData("{ \"test\":\"value\" }", "{\"test\":\"value\"}")]
|
||||||
|
[InlineData("{\"test\":{\"nested\":\"value\"}}", "{\"test\":{\"nested\":\"value\"}}")]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_StringInput_IsValidMatch(string value, string input)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(input).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("{\"test\":\"*\"}", "{\"test\":\"xxx\",\"other\":\"xyz\"}")]
|
||||||
|
[InlineData("\"t*t\"", "\"test\"")]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_StringInputWithWildcard_IsValidMatch(string value, string input)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(input).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("\"test\"", null)]
|
||||||
|
[InlineData("\"test1\"", "\"test2\"")]
|
||||||
|
[InlineData("123", "1234")]
|
||||||
|
[InlineData("[\"test\"]", "[\"test1\"]")]
|
||||||
|
[InlineData("[\"test\"]", "[\"test1\", \"test2\"]")]
|
||||||
|
[InlineData("[123]", "[1234]")]
|
||||||
|
[InlineData("{}", "\"test\"")]
|
||||||
|
[InlineData("{ \"test\":\"value\" }", "{\"test\":\"value2\"}")]
|
||||||
|
[InlineData("{ \"test.nested\":\"value\" }", "{\"test\":{\"nested\":\"value1\"}}")]
|
||||||
|
[InlineData("{\"test\":{\"test1\":\"value\"}}", "{\"test\":{\"test1\":\"value1\"}}")]
|
||||||
|
[InlineData("[{ \"test.nested\":\"value\" }]", "[{\"test\":{\"nested\":\"value1\"}}]")]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_StringInputWithInvalidMatch(string value, string? input)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(input).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("{ \"test.nested\":123 }", "{\"test\":{\"nested\":123}}")]
|
||||||
|
[InlineData("{ \"test.nested\":[123, 456] }", "{\"test\":{\"nested\":[123, 456]}}")]
|
||||||
|
[InlineData("{ \"test.nested\":\"value\" }", "{\"test\":{\"nested\":\"value\"}}")]
|
||||||
|
[InlineData("{ \"['name.with.dot']\":\"value\" }", "{\"name.with.dot\":\"value\"}")]
|
||||||
|
[InlineData("[{ \"test.nested\":\"value\" }]", "[{\"test\":{\"nested\":\"value\"}}]")]
|
||||||
|
[InlineData("[{ \"['name.with.dot']\":\"value\" }]", "[{\"name.with.dot\":\"value\"}]")]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_ValueAsPathValidMatch(string value, string input)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(input).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("{ \"test.nested\":123 }", "{\"test\":{\"nested\":456}}")]
|
||||||
|
[InlineData("{ \"test.nested\":[123, 456] }", "{\"test\":{\"nested\":[1, 2]}}")]
|
||||||
|
[InlineData("{ \"test.nested\":\"value\" }", "{\"test\":{\"nested\":\"value1\"}}")]
|
||||||
|
[InlineData("{ \"['name.with.dot']\":\"value\" }", "{\"name.with.dot\":\"value1\"}")]
|
||||||
|
[InlineData("[{ \"test.nested\":\"value\" }]", "[{\"test\":{\"nested\":\"value1\"}}]")]
|
||||||
|
[InlineData("[{ \"['name.with.dot']\":\"value\" }]", "[{\"name.with.dot\":\"value1\"}]")]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_ValueAsPathInvalidMatch(string value, string input)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(value);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch(input).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(0.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_WithIgnoreCaseTrueAndRegexTrue_JsonObject1()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(new { id = 1, Number = "^\\d+$" }, ignoreCase: true, regex: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{ \"Id\" : 1, \"Number\" : \"42\" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_WithIgnoreCaseTrueAndRegexTrue_JsonObject2()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(new { method = "initialize", id = "^[a-f0-9]{32}-[0-9]$" }, ignoreCase: true, regex: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{\"jsonrpc\":\"2.0\",\"id\":\"ec475f56d4694b48bc737500ba575b35-1\",\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"GitHub Test\",\"version\":\"1.0.0\"}}}").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_JsonElement_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(new { Id = 1, Name = "Test" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var jsonElement = JsonDocument.Parse("{ \"Id\" : 1, \"Name\" : \"Test\", \"Extra\" : \"value\" }").RootElement;
|
||||||
|
var match = matcher.IsMatch(jsonElement).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPartialWildcardMatcher_IsMatch_WithRegexTrue_DateFormat_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var matcher = new SystemTextJsonPartialWildcardMatcher(
|
||||||
|
new { date = "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$", id = 1 },
|
||||||
|
ignoreCase: false,
|
||||||
|
regex: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var match = matcher.IsMatch("{\"date\":\"2026-06-09T22:23:18.53421+00:00\",\"id\":1}").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(1.0, match);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,400 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.Matchers;
|
||||||
|
|
||||||
|
public class SystemTextJsonPathMatcherTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_GetName()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("X");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string name = matcher.Name;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
name.Should().Be("SystemTextJsonPathMatcher");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_GetPatterns()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("X");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var patterns = matcher.GetPatterns();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
patterns.Should().ContainSingle("X");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_ByteArray()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var bytes = new byte[0];
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.Id");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(bytes).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_NullString()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.Id");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(null).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_EmptyString()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.Id");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(string.Empty).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_NullObject()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
object? o = null;
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.Id");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(o).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_String_Exception_Mismatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.Id");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch("not-json").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_AnonymousObject()
|
||||||
|
{
|
||||||
|
// Arrange - RFC 9535: filter expression requires an array context
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$[?(@.Id == 1)]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(new[] { new { Id = 1, Name = "Test" } }).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_AnonymousObject_WithNestedObject()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.things[?(@.name == 'x')]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(new { things = new { name = "x" } }).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_String_WithNestedObject()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var json = "{ \"things\": { \"name\": \"x\" } }";
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.things[?(@.name == 'x')]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(json).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsNoMatch_String_WithNestedObject()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var json = "{ \"things\": { \"name\": \"y\" } }";
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.things[?(@.name == 'x')]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(json).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_JsonNode()
|
||||||
|
{
|
||||||
|
// Arrange - RFC 9535: filter expression requires an array context
|
||||||
|
string[] patterns = { "$[?(@.Id == 1)]" };
|
||||||
|
var matcher = new SystemTextJsonPathMatcher(patterns);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var node = JsonNode.Parse("[{\"Id\":1,\"Name\":\"Test\"}]");
|
||||||
|
double match = matcher.IsMatch(node).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_JsonNode_Parsed()
|
||||||
|
{
|
||||||
|
// Arrange - RFC 9535: filter expression requires an array context
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$[?(@.Id == 1)]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse("[{\"Id\":1,\"Name\":\"Test\"}]")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_RejectOnMatch()
|
||||||
|
{
|
||||||
|
// Arrange - RFC 9535: filter expression requires an array context
|
||||||
|
var matcher = new SystemTextJsonPathMatcher(MatchBehaviour.RejectOnMatch, MatchOperator.Or, "$[?(@.Id == 1)]");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse("[{\"Id\":1,\"Name\":\"Test\"}]")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_ArrayOneLevel()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.arr[0].line1");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse(@"{
|
||||||
|
""name"": ""PathSelectorTest"",
|
||||||
|
""test"": ""test"",
|
||||||
|
""test2"": ""test2"",
|
||||||
|
""arr"": [{
|
||||||
|
""line1"": ""line1""
|
||||||
|
}]
|
||||||
|
}")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_ObjectMatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.test");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse(@"{
|
||||||
|
""name"": ""PathSelectorTest"",
|
||||||
|
""test"": ""test"",
|
||||||
|
""test2"": ""test2"",
|
||||||
|
""arr"": [
|
||||||
|
{
|
||||||
|
""line1"": ""line1""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_DoesntMatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.test3");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse(@"{
|
||||||
|
""name"": ""PathSelectorTest"",
|
||||||
|
""test"": ""test"",
|
||||||
|
""test2"": ""test2"",
|
||||||
|
""arr"": [
|
||||||
|
{
|
||||||
|
""line1"": ""line1""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_DoesntMatchInArray()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$arr[0].line1");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse(@"{
|
||||||
|
""name"": ""PathSelectorTest"",
|
||||||
|
""test"": ""test"",
|
||||||
|
""test2"": ""test2"",
|
||||||
|
""arr"": []
|
||||||
|
}")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_DoesntMatchNoObjectsInArray()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$arr[2].line1");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse(@"{
|
||||||
|
""name"": ""PathSelectorTest"",
|
||||||
|
""test"": ""test"",
|
||||||
|
""test2"": ""test2"",
|
||||||
|
""arr"": []
|
||||||
|
}")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_NestedArrays()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.arr[0].sub[0].subline1");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse(@"{
|
||||||
|
""name"": ""PathSelectorTest"",
|
||||||
|
""test"": ""test"",
|
||||||
|
""test2"": ""test2"",
|
||||||
|
""arr"": [{
|
||||||
|
""line1"": ""line1"",
|
||||||
|
""sub"":[
|
||||||
|
{
|
||||||
|
""subline1"":""subline1""
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_MultiplePatternsUsingMatchOperatorAnd()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher(MatchBehaviour.AcceptOnMatch, MatchOperator.And, "$.arr[0].sub[0].subline1", "$.arr[0].line2");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse(@"{
|
||||||
|
""name"": ""PathSelectorTest"",
|
||||||
|
""test"": ""test"",
|
||||||
|
""test2"": ""test2"",
|
||||||
|
""arr"": [{
|
||||||
|
""line1"": ""line1"",
|
||||||
|
""sub"":[
|
||||||
|
{
|
||||||
|
""subline1"":""subline1""
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_MultiplePatternsUsingMatchOperatorOr()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, "$.arr[0].sub[0].subline2", "$.arr[0].line1");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(JsonNode.Parse(@"{
|
||||||
|
""name"": ""PathSelectorTest"",
|
||||||
|
""test"": ""test"",
|
||||||
|
""test2"": ""test2"",
|
||||||
|
""arr"": [{
|
||||||
|
""line1"": ""line1"",
|
||||||
|
""sub"":[
|
||||||
|
{
|
||||||
|
""subline1"":""subline1""
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}")).Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_String_ArrayOneLevel()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.arr[0].line1");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(@"{
|
||||||
|
""name"": ""PathSelectorTest"",
|
||||||
|
""arr"": [{
|
||||||
|
""line1"": ""line1""
|
||||||
|
}]
|
||||||
|
}").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SystemTextJsonPathMatcher_IsMatch_String_DoesntMatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new SystemTextJsonPathMatcher("$.test3");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double match = matcher.IsMatch(@"{ ""test"": ""test"" }").Score;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
match.Should().Be(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ using WireMock.Server;
|
|||||||
|
|
||||||
namespace WireMock.Net.Tests.Pact;
|
namespace WireMock.Net.Tests.Pact;
|
||||||
|
|
||||||
|
[Collection(nameof(PactTests))]
|
||||||
public class PactTests
|
public class PactTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
@@ -323,7 +322,7 @@ public class RequestBuilderWithBodyTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Request_WithBodyJson_PathMatcher_false()
|
public void Request_WithBodyJson_JsonPathMatcher_false()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"));
|
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"));
|
||||||
@@ -368,10 +367,10 @@ public class RequestBuilderWithBodyTests
|
|||||||
public void Request_WithBody_Array_JsonPathMatcher_1()
|
public void Request_WithBody_Array_JsonPathMatcher_1()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..books[?(@.price < 10)]"));
|
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$[?(@.Id == 1)]"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
string jsonString = "{ \"books\": [ { \"category\": \"test1\", \"price\": 8.95 }, { \"category\": \"test2\", \"price\": 20 } ] }";
|
string jsonString = "[{\"Id\": 1, \"Name\": \"Test\"}, {\"Id\": 2, \"Name\": \"Test2\"}]";
|
||||||
var bodyData = new BodyData
|
var bodyData = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
||||||
@@ -391,10 +390,10 @@ public class RequestBuilderWithBodyTests
|
|||||||
public void Request_WithBody_Array_JsonPathMatcher_2()
|
public void Request_WithBody_Array_JsonPathMatcher_2()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..[?(@.Id == 1)]"));
|
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$.test"));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
string jsonString = "{ \"Id\": 1, \"Name\": \"Test\" }";
|
string jsonString = "{\"name\": \"PathSelectorTest\", \"test\": \"test\", \"test2\": \"test2\", \"arr\": [{\"line1\": \"line1\"}]}";
|
||||||
var bodyData = new BodyData
|
var bodyData = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
||||||
@@ -479,5 +478,132 @@ public class RequestBuilderWithBodyTests
|
|||||||
var requestMatchResult = new RequestMatchResult();
|
var requestMatchResult = new RequestMatchResult();
|
||||||
requestBuilder.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
requestBuilder.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_SystemTextJsonPathMatcher_true()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new SystemTextJsonPathMatcher("$..things[?(@.name == 'RequiredThing')]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
spec.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBodyJson_SystemTextJsonPathMatcher_false()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new SystemTextJsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "{ \"things\": { \"name\": \"Wiremock\" } }",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
spec.GetMatchingScore(request, requestMatchResult).Should().NotBe(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_Object_SystemTextJsonPathMatcher_true()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new SystemTextJsonPathMatcher("$.arr[0].line1"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string jsonString = "{\"name\": \"PathSelectorTest\", \"test\": \"test\", \"test2\": \"test2\", \"arr\": [{\"line1\": \"line1\"}]}";
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = jsonString,
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
spec.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_Array_SystemTextJsonPathMatcher_1()
|
||||||
|
{
|
||||||
|
// Arrange - RFC 9535: filter expression requires an array context
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new SystemTextJsonPathMatcher("$[?(@.Id == 1)]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string jsonString = "[{\"Id\": 1, \"Name\": \"Test\"}, {\"Id\": 2, \"Name\": \"Test2\"}]";
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = jsonString,
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
spec.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_Array_SystemTextJsonPathMatcher_2()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new SystemTextJsonPathMatcher("$.test"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string jsonString = "{\"name\": \"PathSelectorTest\", \"test\": \"test\", \"test2\": \"test2\", \"arr\": [{\"line1\": \"line1\"}]}";
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = jsonString,
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
double result = spec.GetMatchingScore(request, requestMatchResult);
|
||||||
|
result.Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_SystemTextJsonPathMatcher_false()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new SystemTextJsonPathMatcher("$.nonexistent"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string jsonString = "{\"name\": \"Test\", \"arr\": [{\"line1\": \"line1\"}]}";
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = jsonString,
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
spec.GetMatchingScore(request, requestMatchResult).Should().NotBe(1.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user