Compare commits

...

39 Commits

Author SHA1 Message Date
Stef Heyenrath
09a302baf2 1.5.35 2023-08-19 10:00:18 +02:00
Stef Heyenrath
f0139eb837 Update comment in JsonPathMatcher.cs 2023-08-17 17:22:05 +02:00
DayLightDancer
8adf34fb56 Update JSONPathMatcher.cs to cover the string path selection to a child (#993)
* Update JSONPathMatcher.cs to cover the string path selection to a child 

The .SelectToken method accept string path selection and JSONPath queries. The current code works only for the queries because the result is JObject. When the string path is selected the result is JValue and event with a valid result the code the code doesn't return valued result.
https://www.newtonsoft.com/json/help/html/SelectToken.htm

* Added unit tests

* Addressed the comments

* Addressed the comments

* Update JSONPathMatcher.cs
2023-08-17 17:18:32 +02:00
Stef Heyenrath
fd816f0952 Add extra unit test for WithParam multiple values comma (#992) 2023-08-12 21:05:13 +02:00
Stef Heyenrath
205c1d598b 1.5.34 2023-08-04 10:51:51 +02:00
Stef Heyenrath
b986633eca Fix MimeKitLite NuGet include (#989)
* Fix 500

* MimeKiteLite : fix NuGet include

* .
2023-08-04 10:44:53 +02:00
Stef Heyenrath
6aa7aac151 1.5.33 2023-08-03 16:08:50 +02:00
Stef Heyenrath
4688f556b5 Add MultiPart/MimePart Request Matcher (#981)
* wip

* .

* mm

* x

* .

* .

* .

* tests

* .

* more tests

* trans

* x

* win

* fix

* .

* tests
2023-08-03 15:55:46 +02:00
Stef Heyenrath
a58ead7b4e Upgrade to Handlebars.Net.Helpers 2.4.0 to update XPath.SelectTokens and XPath.EvaluateToString (#976)
* Upgrade to Handlebars.Net.Helpers 2.4.0 to update XPath.SelectTokens and XPath.EvaluateToString

* fix
2023-07-20 21:49:00 +02:00
Tymur Nesterenko
58bfb3ea33 JsonPartialMatcher - match guid and string (#972)
* JsonPartialMatcher - match guid and string (#971)

* JsonPartialMatcher - match guid and string. Add Regex with Guid test (#971)
2023-07-19 22:34:02 +02:00
Stef Heyenrath
9c51548d2b 1.5.32 2023-07-15 09:41:05 +02:00
Stef Heyenrath
98b8ede826 Fixed JsonPathMatcher to match nested objects (#966)
* Fixed JsonPathMatcher to match nested objects

* fix

* .

* 100%
2023-07-15 09:29:13 +02:00
Stef Heyenrath
a6f3f976af 1.5.31 2023-07-08 14:57:12 +02:00
Stef Heyenrath
b495eb83b1 Add GraphQL Schema matching (#964)
* Add GrapQLMatcher

* tests

* x

* .

* .

* RequestMessageGraphQLMatcher

* .

* more tests

* tests

* ...

* ms

* .

* more tests

* GraphQL.NET !!!

* .

* executionResult

* nw

* sonarcloud
2023-07-07 21:43:46 +02:00
Stef Heyenrath
9443e4f071 1.5.30 2023-06-28 08:12:10 +02:00
dependabot[bot]
7a914481e5 Bump System.Linq.Dynamic.Core (#963)
Bumps [System.Linq.Dynamic.Core](https://github.com/zzzprojects/System.Linq.Dynamic.Core) from 1.2.23 to 1.3.0.
- [Release notes](https://github.com/zzzprojects/System.Linq.Dynamic.Core/releases)
- [Changelog](https://github.com/zzzprojects/System.Linq.Dynamic.Core/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zzzprojects/System.Linq.Dynamic.Core/compare/v1.2.23...v1.3.0)

---
updated-dependencies:
- dependency-name: System.Linq.Dynamic.Core
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-28 07:58:03 +02:00
dependabot[bot]
1ad836659d Bump System.Linq.Dynamic.Core (#962)
Bumps [System.Linq.Dynamic.Core](https://github.com/zzzprojects/System.Linq.Dynamic.Core) from 1.2.23 to 1.3.0.
- [Release notes](https://github.com/zzzprojects/System.Linq.Dynamic.Core/releases)
- [Changelog](https://github.com/zzzprojects/System.Linq.Dynamic.Core/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zzzprojects/System.Linq.Dynamic.Core/compare/v1.2.23...v1.3.0)

---
updated-dependencies:
- dependency-name: System.Linq.Dynamic.Core
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-28 07:57:50 +02:00
Stef Heyenrath
ed7f9c1143 Add unit-test for Param - MatcherModel - LinqMatcher (#961) 2023-06-27 22:31:14 +02:00
Stef Heyenrath
c92183558b Fixed logic for FluentAssertions WithHeader (#959) 2023-06-23 15:20:57 +02:00
Stef Heyenrath
8ce24249d0 1.5.29 2023-06-22 19:02:10 +02:00
Stef Heyenrath
7ca70309cb Support setting WireMockServerSettings via Environment (#954)
* Support parsing environment variables (WireMockServerSettings__)

* case ignore

* fix

* SimpleSettingsParserTests

* .

* int

* more test
2023-06-22 10:35:21 +02:00
Stef Heyenrath
5d0bf6f4e1 Fix some SonarCloud issues (#955)
* Fixed some SonarCloud issues

* if (value.Contains('\n'))
2023-06-13 19:31:04 +02:00
Stef Heyenrath
f6e35cbe2d 1.5.28 2023-06-11 14:22:54 +02:00
Stef Heyenrath
dc4c8d1dba WireMock.Net.Testcontainers (#948)
* WireMock.Net.Testcontainers

* .

* logger?

* .

* .

* WatchStaticMappings

* linux

* .

* --

* ContainerInfo

* .

* 02

* .

* fix

* .
2023-06-11 13:55:57 +02:00
Stef Heyenrath
adf1914877 Allow setting the Content-Length header for a HTTP method HEAD (#951)
* Allow setting the Content-Length header for a HTTP method HEAD

* .
2023-06-06 22:44:14 +02:00
Stef Heyenrath
1f1bc05f00 1.5.27 2023-06-03 17:00:18 +02:00
Stef Heyenrath
c107e38e3b Fix WireMock.Net.FluentAssertions for net47 2023-06-02 12:03:12 +02:00
Stef Heyenrath
a77c4fe1ac Add ".NET Framework 4.7" to WireMock.Net.FluentAssertions (#949) 2023-06-01 18:06:28 +02:00
Stef Heyenrath
c1e71707c5 Add warning logging when sending a request to a Webhook does not return status 200 (#946) 2023-05-28 10:53:54 +02:00
Oleg Nenashev
69499afe43 Update Slack link (#944)
Better to use https://slack.wiremock.org/ to have proper Slack signup
2023-05-26 10:01:16 +02:00
Stef Heyenrath
aadac78577 add Slack 2023-05-25 23:49:12 +02:00
Stef Heyenrath
71393204cc 1.5.26 2023-05-25 21:36:01 +02:00
Cezary Piątek
e5cc6f570c Code generator improvements (#940)
* Fix quotation marks escaping in multiline string

* Add support for JsonPartialMatcher and JsonPartialWildcardMatcher in mapping code generator
2023-05-25 20:59:13 +02:00
Stef Heyenrath
7c3a0c815d Add GetParameter method to IRequestMessage (#942) 2023-05-25 15:14:02 +02:00
Stef Heyenrath
e61f08fe48 WireMockMiddleware should use HandleRequestsSynchronously correctly (#939) 2023-05-19 21:43:14 +02:00
Stef Heyenrath
11f4c47851 Add more unitests for CSharpFormatter utils (#938)
* Add unit-tests for CSharpFormatter

* .

* t
2023-05-19 16:14:26 +02:00
Stef Heyenrath
3956cd703b 1.5.25 (ReleaseNotes) 2023-05-13 11:17:03 +02:00
Stef Heyenrath
27682d0ce4 1.5.25 + Fixes in CSharpFormatter 2023-05-13 11:15:40 +02:00
Cezary Piątek
8444c8c506 Code generator improvements (#934)
* Handle new line escaping in C# mapping code generator

* Prevent date conversion when value persisted as string

* Handle object properties named as csharp keywords

* Refactor: Extract logic responsible for generating anonymous object definition to a separate class
2023-05-13 09:33:25 +02:00
135 changed files with 5061 additions and 1505 deletions

View File

@@ -1,3 +1,60 @@
# 1.5.35 (19 August 2023)
- [#992](https://github.com/WireMock-Net/WireMock.Net/pull/992) - Add extra unit test for WithParam multiple values comma [test] contributed by [StefH](https://github.com/StefH)
- [#993](https://github.com/WireMock-Net/WireMock.Net/pull/993) - Update JSONPathMatcher.cs to cover the string path selection to a child contributed by [DayLightDancer](https://github.com/DayLightDancer)
# 1.5.34 (04 August 2023)
- [#989](https://github.com/WireMock-Net/WireMock.Net/pull/989) - Fix MimeKitLite NuGet include [bug] contributed by [StefH](https://github.com/StefH)
- [#988](https://github.com/WireMock-Net/WireMock.Net/issues/988) - v1.5.33 Returns always StatusCode 500 [bug]
# 1.5.33 (03 August 2023)
- [#972](https://github.com/WireMock-Net/WireMock.Net/pull/972) - JsonPartialMatcher - match guid and string contributed by [timurnes](https://github.com/timurnes)
- [#976](https://github.com/WireMock-Net/WireMock.Net/pull/976) - Upgrade to Handlebars.Net.Helpers 2.4.0 to update XPath.SelectTokens and XPath.EvaluateToString [feature] contributed by [StefH](https://github.com/StefH)
- [#981](https://github.com/WireMock-Net/WireMock.Net/pull/981) - Add MultiPart/MimePart Request Matcher [feature] contributed by [StefH](https://github.com/StefH)
- [#968](https://github.com/WireMock-Net/WireMock.Net/issues/968) - Using request multipart in response template [feature]
- [#969](https://github.com/WireMock-Net/WireMock.Net/issues/969) - Multipart validation [feature]
- [#970](https://github.com/WireMock-Net/WireMock.Net/issues/970) - Loop through xml elements in handlebars template [feature]
- [#971](https://github.com/WireMock-Net/WireMock.Net/issues/971) - JsonPartialMatcher - match guid and string [feature]
# 1.5.32 (15 July 2023)
- [#966](https://github.com/WireMock-Net/WireMock.Net/pull/966) - Fixed JsonPathMatcher to match nested objects [bug] contributed by [StefH](https://github.com/StefH)
- [#965](https://github.com/WireMock-Net/WireMock.Net/issues/965) - JsonPathMatcher does not match json body nested objects [bug]
- [#967](https://github.com/WireMock-Net/WireMock.Net/issues/967) - &#11088;10 million downloads ! &#11088; [feature]
# 1.5.31 (08 July 2023)
- [#964](https://github.com/WireMock-Net/WireMock.Net/pull/964) - Add GraphQL Schema matching [feature] contributed by [StefH](https://github.com/StefH)
# 1.5.30 (28 June 2023)
- [#959](https://github.com/WireMock-Net/WireMock.Net/pull/959) - Fixed logic for FluentAssertions WithHeader [bug] contributed by [StefH](https://github.com/StefH)
- [#961](https://github.com/WireMock-Net/WireMock.Net/pull/961) - Add unit-test for Param MatcherModel LinqMatcher [test] contributed by [StefH](https://github.com/StefH)
- [#962](https://github.com/WireMock-Net/WireMock.Net/pull/962) - Bump System.Linq.Dynamic.Core from 1.2.23 to 1.3.0 in /examples/WireMock.Net.Console.Net472.Classic [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
- [#963](https://github.com/WireMock-Net/WireMock.Net/pull/963) - Bump System.Linq.Dynamic.Core from 1.2.23 to 1.3.0 in /examples/WireMock.Net.StandAlone.Net461 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
- [#958](https://github.com/WireMock-Net/WireMock.Net/issues/958) - [FluentAssertions] Should().HaveReceivedACall().WithHeader() only checks the first header with the matching key. [bug]
# 1.5.29 (22 June 2023)
- [#954](https://github.com/WireMock-Net/WireMock.Net/pull/954) - Support setting WireMockServerSettings via Environment [feature] contributed by [StefH](https://github.com/StefH)
- [#955](https://github.com/WireMock-Net/WireMock.Net/pull/955) - Fix some SonarCloud issues [refactor] contributed by [StefH](https://github.com/StefH)
- [#953](https://github.com/WireMock-Net/WireMock.Net/issues/953) - How to use environment variable [feature]
# 1.5.28 (11 June 2023)
- [#948](https://github.com/WireMock-Net/WireMock.Net/pull/948) - WireMock.Net.Testcontainers [feature] contributed by [StefH](https://github.com/StefH)
- [#951](https://github.com/WireMock-Net/WireMock.Net/pull/951) - Allow setting the Content-Length header for a HTTP method HEAD [feature] contributed by [StefH](https://github.com/StefH)
# 1.5.27 (03 June 2023)
- [#946](https://github.com/WireMock-Net/WireMock.Net/pull/946) - Add warning logging when sending a request to a Webhook does not return status 200 [feature] contributed by [StefH](https://github.com/StefH)
- [#949](https://github.com/WireMock-Net/WireMock.Net/pull/949) - Add &quot;.NET Framework 4.7&quot; to WireMock.Net.FluentAssertions [feature] contributed by [StefH](https://github.com/StefH)
- [#928](https://github.com/WireMock-Net/WireMock.Net/issues/928) - TypeLoadException when using WithHeader method. [bug]
- [#945](https://github.com/WireMock-Net/WireMock.Net/issues/945) - Webhook logging [feature]
# 1.5.26 (25 May 2023)
- [#938](https://github.com/WireMock-Net/WireMock.Net/pull/938) - Add more unitests for CSharpFormatter utils [test] contributed by [StefH](https://github.com/StefH)
- [#939](https://github.com/WireMock-Net/WireMock.Net/pull/939) - WireMockMiddleware should use HandleRequestsSynchronously correctly [bug] contributed by [StefH](https://github.com/StefH)
- [#940](https://github.com/WireMock-Net/WireMock.Net/pull/940) - Code generator improvements contributed by [cezarypiatek](https://github.com/cezarypiatek)
- [#942](https://github.com/WireMock-Net/WireMock.Net/pull/942) - Add GetParameter method to IRequestMessage [feature] contributed by [StefH](https://github.com/StefH)
- [#941](https://github.com/WireMock-Net/WireMock.Net/issues/941) - RequestMessage.GetParameter method missing from IRequestMessage interface [feature]
# 1.5.25 (13 May 2023)
- [#934](https://github.com/WireMock-Net/WireMock.Net/pull/934) - Code generator improvements [feature] contributed by [cezarypiatek](https://github.com/cezarypiatek)
# 1.5.24 (07 May 2023)
- [#926](https://github.com/WireMock-Net/WireMock.Net/pull/926) - Fix C# mapping code generator for header names [bug] contributed by [cezarypiatek](https://github.com/cezarypiatek)
- [#927](https://github.com/WireMock-Net/WireMock.Net/pull/927) - Enrich generated code with status code [feature] contributed by [cezarypiatek](https://github.com/cezarypiatek)
@@ -930,7 +987,7 @@
- [#86](https://github.com/WireMock-Net/WireMock.Net/issues/86) - Feature : Add FileSystemWatcher logic for watching static mapping files [feature]
# 1.0.2.13 (23 January 2018)
- [#79](https://github.com/WireMock-Net/WireMock.Net/pull/79) - Fix missed content headers contributed by [vladimir-fed](https://github.com/vladimir-fed)
- [#79](https://github.com/WireMock-Net/WireMock.Net/pull/79) - Fix missed content headers contributed by [volodymyr-fed](https://github.com/volodymyr-fed)
- [#57](https://github.com/WireMock-Net/WireMock.Net/issues/57) - ProxyAndRecord does not save query-parameters, headers and body [bug]
- [#78](https://github.com/WireMock-Net/WireMock.Net/issues/78) - WireMock not working when attempting to access from anything other than localhost.
@@ -957,7 +1014,7 @@
# 1.0.2.7 (18 November 2017)
- [#62](https://github.com/WireMock-Net/WireMock.Net/pull/62) - Add the Host, Protocol, Port and Origin to the Request message so they can be used in templating contributed by [alastairtree](https://github.com/alastairtree)
- [#63](https://github.com/WireMock-Net/WireMock.Net/pull/63) - Fix issue with concurrent logging contributed by [vladimir-fed](https://github.com/vladimir-fed)
- [#63](https://github.com/WireMock-Net/WireMock.Net/pull/63) - Fix issue with concurrent logging contributed by [volodymyr-fed](https://github.com/volodymyr-fed)
- [#27](https://github.com/WireMock-Net/WireMock.Net/issues/27) - New feature: Record and Save
- [#42](https://github.com/WireMock-Net/WireMock.Net/issues/42) - Enhancement - Save/load request logs to/from disk [feature]
- [#53](https://github.com/WireMock-Net/WireMock.Net/issues/53) - New feature request: Access to Owin pipeline

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.5.24</VersionPrefix>
<VersionPrefix>1.5.35</VersionPrefix>
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>

View File

@@ -1,6 +1,6 @@
rem https://github.com/StefH/GitHubReleaseNotes
SET version=1.5.24
SET version=1.5.35
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate --version %version% --token %GH_TOKEN%

View File

@@ -1,8 +1,5 @@
# 1.5.24 (07 May 2023)
- #926 Fix C# mapping code generator for header names [bug]
- #927 Enrich generated code with status code [feature]
- #930 Update C# mapping code generator for WithStatusCode [feature]
- #931 Add property 'IsStartedWithAdminInterface' to 'IWireMockServer' [feature]
- #933 C# code generator improvements [feature]
# 1.5.35 (19 August 2023)
- #992 Add extra unit test for WithParam multiple values comma [test]
- #993 Update JSONPathMatcher.cs to cover the string path selection to a child
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -22,7 +22,7 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
| | |
| --- | --- |
| ***Project*** | &nbsp; |
| &nbsp;&nbsp;**Chat** | [![Gitter](https://img.shields.io/gitter/room/wiremock_dotnet/Lobby.svg)](https://gitter.im/wiremock_dotnet/Lobby) |
| &nbsp;&nbsp;**Chat** | [![Slack](https://badgen.net/badge/icon/slack?icon=slack&label)](https://slack.wiremock.org/) [![Gitter](https://img.shields.io/gitter/room/wiremock_dotnet/Lobby.svg)](https://gitter.im/wiremock_dotnet/Lobby) |
| &nbsp;&nbsp;**Issues** | [![GitHub issues](https://img.shields.io/github/issues/WireMock-Net/WireMock.Net.svg)](https://github.com/WireMock-Net/WireMock.Net/issues) |
| | |
| ***Quality*** | &nbsp; |
@@ -42,6 +42,7 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
| &nbsp;&nbsp;**WireMock.Net.OpenApiParser** | [![NuGet Badge WireMock.Net.OpenApiParser](https://buildstats.info/nuget/WireMock.Net.OpenApiParser)](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [![MyGet Badge WireMock.Net.OpenApiParser](https://buildstats.info/myget/wiremock-net/WireMock.Net.OpenApiParser?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser)
| &nbsp;&nbsp;**WireMock.Net.RestClient** | [![NuGet Badge WireMock.Net.RestClient](https://buildstats.info/nuget/WireMock.Net.RestClient)](https://www.nuget.org/packages/WireMock.Net.RestClient) | [![MyGet Badge WireMock.Net.RestClient](https://buildstats.info/myget/wiremock-net/WireMock.Net.RestClient?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
| &nbsp;&nbsp;**WireMock.Net.xUnit** | [![NuGet Badge WireMock.Net.xUnit](https://buildstats.info/nuget/WireMock.Net.xUnit)](https://www.nuget.org/packages/WireMock.Net.xUnit) | [![MyGet Badge WireMock.Net.xUnit](https://buildstats.info/myget/wiremock-net/WireMock.Net.xUnit?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.xUnit)
| &nbsp;&nbsp;**WireMock.Net.Testcontainers** | [![NuGet Badge WireMock.Net.Testcontainers](https://buildstats.info/nuget/WireMock.Net.Testcontainers)](https://www.nuget.org/packages/WireMock.Net.Testcontainers) | [![MyGet Badge WireMock.Net.Testcontainers](https://buildstats.info/myget/wiremock-net/WireMock.Net.Testcontainers?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Testcontainers)
| &nbsp;&nbsp;**WireMock.Org.RestClient** | [![NuGet Badge WireMock.Org.RestClient](https://buildstats.info/nuget/WireMock.Org.RestClient)](https://www.nuget.org/packages/WireMock.Org.RestClient) | [![MyGet Badge WireMock.Org.RestClient](https://buildstats.info/myget/wiremock-net/WireMock.Org.RestClient?includePreReleases=true)](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient)
@@ -68,13 +69,15 @@ WireMock.Net can be used in several ways:
You can use your favorite test framework and use WireMock within your tests, see
[Wiki : UnitTesting](https://github.com/StefH/WireMock.Net/wiki/Using-WireMock-in-UnitTests).
### Unit/Integration Testing using Testcontainers.DotNet
You can use [Wiki : WireMock.Net.Testcontainers](https://github.com/WireMock-Net/WireMock.Net/wiki/Using-WireMock.Net.Testcontainers) to build a WireMock.Net Docker container which can be used in Unit/Integration testing.
### As a dotnet tool
It's simple to install WireMock.Net as (global) dotnet tool, see [Wiki : dotnet tool](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-dotnet-tool).
### As standalone process / console application
This is quite straight forward to launch a mock server within a console application, see [Wiki : Standalone Process](https://github.com/StefH/WireMock.Net/wiki/WireMock-as-a-standalone-process).
### As a Windows Service
You can also run WireMock.Net as a Windows Service, follow this [WireMock-as-a-Windows-Service](https://github.com/WireMock-Net/WireMock.Net/wiki/WireMock-as-a-Windows-Service).

View File

@@ -111,6 +111,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueExample",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueProxy", "examples\WireMockAzureQueueProxy\WireMockAzureQueueProxy.csproj", "{ADB557D8-D66B-4387-912B-3F73E290B478}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Testcontainers", "src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj", "{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.TestcontainersExample", "examples\WireMock.Net.TestcontainersExample\WireMock.Net.TestcontainersExample.csproj", "{56A38798-C48B-4A4A-B805-071E05C02CE1}"
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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Console.NET7.UsingNuGet", "examples\WireMock.Net.Console.NET7.UsingNuGet\WireMock.Net.Console.NET7.UsingNuGet.csproj", "{941229D6-191B-4B5E-AC81-0905EBF4F19D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -265,6 +275,22 @@ Global
{ADB557D8-D66B-4387-912B-3F73E290B478}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADB557D8-D66B-4387-912B-3F73E290B478}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADB557D8-D66B-4387-912B-3F73E290B478}.Release|Any CPU.Build.0 = Release|Any CPU
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}.Release|Any CPU.Build.0 = Release|Any CPU
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|Any CPU.Build.0 = Release|Any CPU
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|Any CPU.Build.0 = Release|Any CPU
{941229D6-191B-4B5E-AC81-0905EBF4F19D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{941229D6-191B-4B5E-AC81-0905EBF4F19D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{941229D6-191B-4B5E-AC81-0905EBF4F19D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{941229D6-191B-4B5E-AC81-0905EBF4F19D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -309,6 +335,10 @@ Global
{7C2A9DE8-C89F-4841-9058-6B9BF81E5E34} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{BAA9EC2A-874B-45CE-8E51-A73622DC7F3D} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{ADB557D8-D66B-4387-912B-3F73E290B478} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
{56A38798-C48B-4A4A-B805-071E05C02CE1} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
{07C30227-ADEC-4BDE-8CDC-849D85A690BB} = {0147029F-FA4A-44B3-B79A-3C3574054EE4}
{941229D6-191B-4B5E-AC81-0905EBF4F19D} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}

View File

@@ -10,9 +10,11 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MD/@EntryIndexedValue">MD5</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OPTIONS/@EntryIndexedValue">OPTIONS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OS/@EntryIndexedValue">OS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PATCH/@EntryIndexedValue">PATCH</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=POST/@EntryIndexedValue">POST</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PUT/@EntryIndexedValue">PUT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QL/@EntryIndexedValue">QL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RSA/@EntryIndexedValue">RSA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SSL/@EntryIndexedValue">SSL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TE/@EntryIndexedValue">TE</s:String>
@@ -32,6 +34,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Raml/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=randomizer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Scriban/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=sheyenrath/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sigil/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stef/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=templated/@EntryIndexedValue">True</s:Boolean>

View File

@@ -73,7 +73,6 @@ class Program
var settingsViaBuilder = new SettingsModelBuilder()
.WithGlobalProcessingDelay(1077)
.WithoutGlobalProcessingDelay()
.Build();
settings1.GlobalProcessingDelay = 1077;

View File

@@ -28,10 +28,10 @@
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="Handlebars.Net.Helpers" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers" Version="2.4.0" />
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -3,6 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
</PropertyGroup>
<ItemGroup>
@@ -27,10 +28,8 @@
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<!--<PackageReference Include="Handlebars.Net.Helpers" Version="2.*" />-->
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,34 @@
using System.Net;
using System.Text;
using FluentAssertions;
using WireMock.Logging;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;
namespace WireMock.Net.Console.NET7.UsingNuGet;
internal class Program
{
private static async Task Main(string[] args)
{
var server = WireMockServer.Start(new WireMockServerSettings
{
Logger = new WireMockConsoleLogger(),
});
server.Given(Request.Create().UsingPost().WithPath("/some/endpoint"))
.RespondWith(Response.Create().WithStatusCode(HttpStatusCode.Created));
var httpClient = new HttpClient { BaseAddress = new Uri(server.Url!) };
var requestUri = new Uri(httpClient.BaseAddress!, "some/endpoint");
var content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
// Act
var actual = await httpClient.PostAsync(requestUri, content);
// Assert
actual.StatusCode.Should().Be(HttpStatusCode.Created);
}
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="WireMock.Net" Version="1.5.32" />
</ItemGroup>
</Project>

View File

@@ -19,14 +19,14 @@
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="Handlebars.Net.Helpers" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.3.*" />
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.3.*" />
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.3.*" />
<PackageReference Include="Handlebars.Net.Helpers" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.4.0" />
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -31,14 +31,14 @@
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="Handlebars.Net.Helpers" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.3.*" />
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.3.*" />
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.3.*" />
<PackageReference Include="Handlebars.Net.Helpers" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.4.0" />
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -28,14 +28,14 @@
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<PackageReference Include="Handlebars.Net.Helpers" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.3.*" />
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.*" />
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.3.*" />
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.3.*" />
<PackageReference Include="Handlebars.Net.Helpers" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.4.0" />
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -42,6 +42,36 @@ namespace WireMock.Net.ConsoleApplication
public static class MainApp
{
private const string TestSchema = @"
input MessageInput {
content: String
author: String
}
type Message {
id: ID!
content: String
author: String
}
type Mutation {
createMessage(input: MessageInput): Message
updateMessage(id: ID!, input: MessageInput): Message
}
type Query {
greeting:String
students:[Student]
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
}";
public static void Run()
{
var mappingBuilder = new MappingBuilder();
@@ -136,7 +166,51 @@ namespace WireMock.Net.ConsoleApplication
//server.SetAzureADAuthentication("6c2a4722-f3b9-4970-b8fc-fac41e29stef", "8587fde1-7824-42c7-8592-faf92b04stef");
// server.AllowPartialMapping();
#if GRAPHQL
server
.Given(Request.Create()
.WithPath("/graphql")
.UsingPost()
.WithGraphQLSchema(TestSchema)
)
.RespondWith(Response.Create()
.WithBody("GraphQL is ok")
);
#endif
#if MIMEKIT
var textPlainContentTypeMatcher = new ContentTypeMatcher("text/plain");
var textPlainContentMatcher = new ExactMatcher("This is some plain text");
var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher);
var textJsonContentTypeMatcher = new ContentTypeMatcher("text/json");
var textJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true);
var textJsonMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textJsonContentTypeMatcher, null, null, textJsonContentMatcher);
var imagePngContentTypeMatcher = new ContentTypeMatcher("image/png");
var imagePngContentDispositionMatcher = new ExactMatcher("attachment; filename=\"image.png\"");
var imagePngContentTransferEncodingMatcher = new ExactMatcher("base64");
var imagePngContentMatcher = new ExactObjectMatcher(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC"));
var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, imagePngContentTypeMatcher, imagePngContentDispositionMatcher, imagePngContentTransferEncodingMatcher, imagePngContentMatcher);
var matchers = new IMatcher[]
{
textPlainMatcher,
textJsonMatcher,
imagePngMatcher
};
server
.Given(Request.Create()
.WithPath("/multipart")
.UsingPost()
.WithMultiPart(matchers)
)
.WithGuid("b9c82182-e469-41da-bcaf-b6e3157fefdb")
.RespondWith(Response.Create()
.WithBody("MultiPart is ok")
);
#endif
// 400 ms
server
.Given(Request.Create()
@@ -676,8 +750,9 @@ namespace WireMock.Net.ConsoleApplication
}));
server.Given(Request.Create().WithPath(new WildcardMatcher("/multi-webhook", true)).UsingPost())
.WithWebhook(new[] {
new Webhook()
.WithWebhook
(
new Webhook
{
Request = new WebhookRequest
{
@@ -685,12 +760,13 @@ namespace WireMock.Net.ConsoleApplication
Method = "post",
BodyData = new BodyData
{
BodyAsString = "OK 1!", DetectedBodyType = BodyType.String
BodyAsString = "OK 1!",
DetectedBodyType = BodyType.String
},
Delay = 1000
}
},
new Webhook()
new Webhook
{
Request = new WebhookRequest
{
@@ -705,7 +781,7 @@ namespace WireMock.Net.ConsoleApplication
MaximumRandomDelay = 7000
}
}
})
)
.WithWebhookFireAndForget(true)
.RespondWith(Response.Create().WithBody("a-response"));

View File

@@ -39,14 +39,14 @@
<Reference Include="AnyOf, Version=0.3.0.0, Culture=neutral, PublicKeyToken=b35e6abbb527c6b1, processorArchitecture=MSIL">
<HintPath>..\..\packages\AnyOf.0.3.0\lib\net45\AnyOf.dll</HintPath>
</Reference>
<Reference Include="Handlebars, Version=2.1.2.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.2\lib\net452\Handlebars.dll</HintPath>
<Reference Include="Handlebars, Version=2.1.4.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.4\lib\net452\Handlebars.dll</HintPath>
</Reference>
<Reference Include="Handlebars.Net.Helpers, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.2.3.12\lib\net452\Handlebars.Net.Helpers.dll</HintPath>
<Reference Include="Handlebars.Net.Helpers, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.2.4.0\lib\net452\Handlebars.Net.Helpers.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Core, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Core.2.3.12\lib\net452\HandlebarsDotNet.Helpers.Core.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Core, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Core.2.4.0\lib\net452\HandlebarsDotNet.Helpers.Core.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=2.0.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\..\packages\log4net.2.0.15\lib\net45\log4net.dll</HintPath>
@@ -56,7 +56,7 @@
<HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.3.1.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SimMetrics.Net, Version=1.0.5.0, Culture=neutral, PublicKeyToken=c58dc06d59f3391b, processorArchitecture=MSIL">
<HintPath>..\..\packages\SimMetrics.Net.1.0.5\lib\net45\SimMetrics.Net.dll</HintPath>
@@ -67,6 +67,7 @@
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AnyOf" version="0.3.0" targetFramework="net452" />
<package id="Handlebars.Net" version="2.1.2" targetFramework="net452" />
<package id="Handlebars.Net.Helpers" version="2.3.12" targetFramework="net452" />
<package id="Handlebars.Net.Helpers.Core" version="2.3.12" targetFramework="net452" />
<package id="Handlebars.Net" version="2.1.4" targetFramework="net452" />
<package id="Handlebars.Net.Helpers" version="2.4.0" targetFramework="net452" />
<package id="Handlebars.Net.Helpers.Core" version="2.4.0" targetFramework="net452" />
<package id="log4net" version="2.0.15" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="3.1.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net452" />
<package id="SimMetrics.Net" version="1.0.5" targetFramework="net452" />
<package id="Stef.Validation" version="0.1.1" targetFramework="net452" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net452" />

View File

@@ -38,14 +38,14 @@
<Reference Include="AnyOf, Version=0.3.0.0, Culture=neutral, PublicKeyToken=b35e6abbb527c6b1, processorArchitecture=MSIL">
<HintPath>..\..\packages\AnyOf.0.3.0\lib\net45\AnyOf.dll</HintPath>
</Reference>
<Reference Include="Handlebars, Version=2.1.2.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.2\lib\net46\Handlebars.dll</HintPath>
<Reference Include="Handlebars, Version=2.1.4.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.4\lib\net46\Handlebars.dll</HintPath>
</Reference>
<Reference Include="Handlebars.Net.Helpers, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.2.3.12\lib\net46\Handlebars.Net.Helpers.dll</HintPath>
<Reference Include="Handlebars.Net.Helpers, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.2.4.0\lib\net46\Handlebars.Net.Helpers.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Core, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Core.2.3.12\lib\net46\HandlebarsDotNet.Helpers.Core.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Core, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Core.2.4.0\lib\net46\HandlebarsDotNet.Helpers.Core.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=2.0.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\..\packages\log4net.2.0.15\lib\net45\log4net.dll</HintPath>
@@ -54,7 +54,7 @@
<HintPath>..\..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SimMetrics.Net, Version=1.0.5.0, Culture=neutral, PublicKeyToken=c58dc06d59f3391b, processorArchitecture=MSIL">
<HintPath>..\..\packages\SimMetrics.Net.1.0.5\lib\net45\SimMetrics.Net.dll</HintPath>

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AnyOf" version="0.3.0" targetFramework="net461" />
<package id="Handlebars.Net" version="2.1.2" targetFramework="net461" />
<package id="Handlebars.Net.Helpers" version="2.3.12" targetFramework="net461" />
<package id="Handlebars.Net.Helpers.Core" version="2.3.12" targetFramework="net461" />
<package id="Handlebars.Net" version="2.1.4" targetFramework="net461" />
<package id="Handlebars.Net.Helpers" version="2.4.0" targetFramework="net461" />
<package id="Handlebars.Net.Helpers.Core" version="2.4.0" targetFramework="net461" />
<package id="log4net" version="2.0.15" targetFramework="net461" />
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.2.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net461" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net461" />
<package id="SimMetrics.Net" version="1.0.5" targetFramework="net461" />
<package id="Stef.Validation" version="0.1.1" targetFramework="net461" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />

View File

@@ -101,6 +101,10 @@
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.25.0.0" newVersion="6.25.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="NJsonSchema" publicKeyToken="c2f9c3bdfae56102" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.7.2.0" newVersion="10.7.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -46,32 +46,32 @@
<Reference Include="Fare, Version=2.2.0.0, Culture=neutral, PublicKeyToken=ea68d375bf33a7c8, processorArchitecture=MSIL">
<HintPath>..\..\packages\Fare.2.2.1\lib\net35\Fare.dll</HintPath>
</Reference>
<Reference Include="Handlebars, Version=2.1.2.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.2\lib\net46\Handlebars.dll</HintPath>
<Reference Include="Handlebars, Version=2.1.4.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.4\lib\net46\Handlebars.dll</HintPath>
</Reference>
<Reference Include="Handlebars.Net.Helpers, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.2.3.12\lib\net46\Handlebars.Net.Helpers.dll</HintPath>
<Reference Include="Handlebars.Net.Helpers, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.2.4.0\lib\net46\Handlebars.Net.Helpers.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Core, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Core.2.3.12\lib\net46\HandlebarsDotNet.Helpers.Core.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Core, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Core.2.4.0\lib\net46\HandlebarsDotNet.Helpers.Core.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.DynamicLinq, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.DynamicLinq.2.3.12\lib\net46\HandlebarsDotNet.Helpers.DynamicLinq.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.DynamicLinq, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.DynamicLinq.2.4.0\lib\net46\HandlebarsDotNet.Helpers.DynamicLinq.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Humanizer, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Humanizer.2.3.12\lib\net46\HandlebarsDotNet.Helpers.Humanizer.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Humanizer, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Humanizer.2.4.0\lib\net46\HandlebarsDotNet.Helpers.Humanizer.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Json, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Json.2.3.12\lib\net46\HandlebarsDotNet.Helpers.Json.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Json, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Json.2.4.0\lib\net46\HandlebarsDotNet.Helpers.Json.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Random, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Random.2.3.12\lib\net46\HandlebarsDotNet.Helpers.Random.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Random, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Random.2.4.0\lib\net46\HandlebarsDotNet.Helpers.Random.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.Xeger, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Xeger.2.3.12\lib\net46\HandlebarsDotNet.Helpers.Xeger.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.Xeger, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.Xeger.2.4.0\lib\net46\HandlebarsDotNet.Helpers.Xeger.dll</HintPath>
</Reference>
<Reference Include="HandlebarsDotNet.Helpers.XPath, Version=2.3.12.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.XPath.2.3.12\lib\net46\HandlebarsDotNet.Helpers.XPath.dll</HintPath>
<Reference Include="HandlebarsDotNet.Helpers.XPath, Version=2.4.0.0, Culture=neutral, PublicKeyToken=00d131fae0c250bc, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.Helpers.XPath.2.4.0\lib\net46\HandlebarsDotNet.Helpers.XPath.dll</HintPath>
</Reference>
<Reference Include="Humanizer, Version=2.14.0.0, Culture=neutral, PublicKeyToken=979442b78dfc278e, processorArchitecture=MSIL">
<HintPath>..\..\packages\Humanizer.Core.2.14.1\lib\netstandard2.0\Humanizer.dll</HintPath>
@@ -257,16 +257,16 @@
<HintPath>..\..\packages\Namotion.Reflection.2.0.10\lib\net45\Namotion.Reflection.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NJsonSchema, Version=10.6.10.0, Culture=neutral, PublicKeyToken=c2f9c3bdfae56102, processorArchitecture=MSIL">
<HintPath>..\..\packages\NJsonSchema.10.6.10\lib\net45\NJsonSchema.dll</HintPath>
<Reference Include="NJsonSchema, Version=10.7.2.0, Culture=neutral, PublicKeyToken=c2f9c3bdfae56102, processorArchitecture=MSIL">
<HintPath>..\..\packages\NJsonSchema.10.7.2\lib\net45\NJsonSchema.dll</HintPath>
</Reference>
<Reference Include="NJsonSchema.Extensions, Version=0.1.0.0, Culture=neutral, PublicKeyToken=e52fadf300daf456, processorArchitecture=MSIL">
<HintPath>..\..\packages\NJsonSchema.Extensions.0.1.0\lib\net45\NJsonSchema.Extensions.dll</HintPath>
</Reference>
<Reference Include="NSwag.Core, Version=13.15.10.0, Culture=neutral, PublicKeyToken=c2d88086e098d109, processorArchitecture=MSIL">
<HintPath>..\..\packages\NSwag.Core.13.15.10\lib\net45\NSwag.Core.dll</HintPath>
<Reference Include="NSwag.Core, Version=13.16.1.0, Culture=neutral, PublicKeyToken=c2d88086e098d109, processorArchitecture=MSIL">
<HintPath>..\..\packages\NSwag.Core.13.16.1\lib\net45\NSwag.Core.dll</HintPath>
</Reference>
<Reference Include="RandomDataGenerator, Version=1.0.16.0, Culture=neutral, PublicKeyToken=ae5c571d29a3b8d9, processorArchitecture=MSIL">
<HintPath>..\..\packages\RandomDataGenerator.Net.1.0.17\lib\net45\RandomDataGenerator.dll</HintPath>
@@ -302,8 +302,8 @@
<Reference Include="System.IO.Pipelines, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.IO.Pipelines.4.5.3\lib\netstandard2.0\System.IO.Pipelines.dll</HintPath>
</Reference>
<Reference Include="System.Linq.Dynamic.Core, Version=1.2.23.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Linq.Dynamic.Core.1.2.23\lib\net46\System.Linq.Dynamic.Core.dll</HintPath>
<Reference Include="System.Linq.Dynamic.Core, Version=1.3.1.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Linq.Dynamic.Core.1.3.1\lib\net46\System.Linq.Dynamic.Core.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>

View File

@@ -2,15 +2,15 @@
<packages>
<package id="AnyOf" version="0.3.0" targetFramework="net472" />
<package id="Fare" version="2.2.1" targetFramework="net472" />
<package id="Handlebars.Net" version="2.1.2" targetFramework="net472" />
<package id="Handlebars.Net.Helpers" version="2.3.12" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Core" version="2.3.12" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.DynamicLinq" version="2.3.12" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Humanizer" version="2.3.12" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Json" version="2.3.12" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Random" version="2.3.12" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Xeger" version="2.3.12" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.XPath" version="2.3.12" targetFramework="net472" />
<package id="Handlebars.Net" version="2.1.4" targetFramework="net472" />
<package id="Handlebars.Net.Helpers" version="2.4.0" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Core" version="2.4.0" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.DynamicLinq" version="2.4.0" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Humanizer" version="2.4.0" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Json" version="2.4.0" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Random" version="2.4.0" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.Xeger" version="2.4.0" targetFramework="net472" />
<package id="Handlebars.Net.Helpers.XPath" version="2.4.0" targetFramework="net472" />
<package id="Humanizer" version="2.14.1" targetFramework="net472" />
<package id="Humanizer.Core" version="2.14.1" targetFramework="net472" />
<package id="Humanizer.Core.af" version="2.14.1" targetFramework="net472" />
@@ -123,10 +123,10 @@
<package id="Microsoft.IdentityModel.Tokens" version="6.25.0" targetFramework="net472" />
<package id="Microsoft.Net.Http.Headers" version="2.2.0" targetFramework="net472" />
<package id="Namotion.Reflection" version="2.0.10" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
<package id="NJsonSchema" version="10.6.10" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net472" />
<package id="NJsonSchema" version="10.7.2" targetFramework="net472" />
<package id="NJsonSchema.Extensions" version="0.1.0" targetFramework="net472" />
<package id="NSwag.Core" version="13.15.10" targetFramework="net472" />
<package id="NSwag.Core" version="13.16.1" targetFramework="net472" />
<package id="Nullable" version="1.3.1" targetFramework="net472" developmentDependency="true" />
<package id="RandomDataGenerator.Net" version="1.0.17" targetFramework="net472" />
<package id="Scriban.Signed" version="2.1.4" targetFramework="net472" />
@@ -138,7 +138,7 @@
<package id="System.Diagnostics.DiagnosticSource" version="4.5.0" targetFramework="net472" />
<package id="System.IdentityModel.Tokens.Jwt" version="6.25.0" targetFramework="net472" />
<package id="System.IO.Pipelines" version="4.5.3" targetFramework="net472" />
<package id="System.Linq.Dynamic.Core" version="1.2.23" targetFramework="net472" />
<package id="System.Linq.Dynamic.Core" version="1.3.1" targetFramework="net472" />
<package id="System.Memory" version="4.5.4" targetFramework="net472" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
<package id="System.Reflection.Metadata" version="1.6.0" targetFramework="net472" />

View File

@@ -9,7 +9,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -72,7 +72,7 @@
<HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.3.1.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Owin.Host.HttpListener" version="3.1.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net452" />
</packages>

View File

@@ -46,7 +46,7 @@
<HintPath>..\..\packages\Microsoft.Owin.Hosting.2.0.2\lib\net45\Microsoft.Owin.Hosting.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>

View File

@@ -8,7 +8,7 @@
<package id="Microsoft.Owin" version="4.2.2" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="2.0.2" targetFramework="net452" />
<package id="Microsoft.Owin.Hosting" version="2.0.2" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
<package id="Owin" version="1.0" targetFramework="net452" />
<package id="SimMetrics.Net" version="1.0.5" targetFramework="net452" />
<package id="System.Net.Http" version="4.3.4" targetFramework="net452" requireReinstallation="true" />

View File

@@ -29,7 +29,7 @@ static class Program
XmlConfigurator.Configure(LogRepository, new FileInfo("log4net.config"));
if (!WireMockServerSettingsParser.TryParseArguments(args, out var settings, new WireMockLog4NetLogger()))
if (!WireMockServerSettingsParser.TryParseArguments(args, Environment.GetEnvironmentVariables(), out var settings, new WireMockLog4NetLogger()))
{
return;
}

View File

@@ -13,7 +13,7 @@ public class Program
{
XmlConfigurator.Configure(new FileInfo("log4net.config"));
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings))
if (WireMockServerSettingsParser.TryParseArguments(args, Environment.GetEnvironmentVariables(), out var settings))
{
Console.WriteLine("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));

View File

@@ -46,7 +46,7 @@
<HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.4.0.0\lib\net451\Microsoft.Owin.Host.HttpListener.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />

View File

@@ -3,5 +3,5 @@
<package id="log4net" version="2.0.15" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.6" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="4.0.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net452" />
</packages>

View File

@@ -9,7 +9,7 @@ static class Program
{
static void Main(string[] args)
{
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings))
if (WireMockServerSettingsParser.TryParseArguments(args, Environment.GetEnvironmentVariables(), out var settings))
{
Console.WriteLine("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));

View File

@@ -39,8 +39,8 @@
<StartupObject>WireMock.Net.StandAlone.Net461.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="Handlebars, Version=2.1.2.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.2\lib\net46\Handlebars.dll</HintPath>
<Reference Include="Handlebars, Version=2.1.4.0, Culture=neutral, PublicKeyToken=22225d0bf33cd661, processorArchitecture=MSIL">
<HintPath>..\..\packages\Handlebars.Net.2.1.4\lib\net46\Handlebars.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNetCore.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.dll</HintPath>
@@ -205,7 +205,7 @@
<HintPath>..\..\packages\MimeKitLite.2.0.7\lib\net45\MimeKitLite.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
@@ -235,8 +235,8 @@
<Reference Include="System.IO.Pipelines, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.IO.Pipelines.4.5.3\lib\netstandard2.0\System.IO.Pipelines.dll</HintPath>
</Reference>
<Reference Include="System.Linq.Dynamic.Core, Version=1.2.23.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Linq.Dynamic.Core.1.2.23\lib\net46\System.Linq.Dynamic.Core.dll</HintPath>
<Reference Include="System.Linq.Dynamic.Core, Version=1.3.1.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Linq.Dynamic.Core.1.3.1\lib\net46\System.Linq.Dynamic.Core.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Handlebars.Net" version="2.1.2" targetFramework="net461" />
<package id="Handlebars.Net" version="2.1.4" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.9" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.9" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Owin" version="5.2.9" targetFramework="net461" />
@@ -59,7 +59,7 @@
<package id="Microsoft.Owin.Host.HttpListener" version="4.2.2" targetFramework="net461" />
<package id="Microsoft.Owin.Hosting" version="4.2.2" targetFramework="net461" />
<package id="MimeKitLite" version="2.0.7" targetFramework="net461" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net461" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net461" />
<package id="Owin" version="1.0" targetFramework="net461" />
<package id="RestEase" version="1.5.7" targetFramework="net461" />
<package id="SimMetrics.Net" version="1.0.5" targetFramework="net461" />
@@ -68,7 +68,7 @@
<package id="System.ComponentModel.Annotations" version="4.5.0" targetFramework="net461" />
<package id="System.Diagnostics.DiagnosticSource" version="4.5.1" targetFramework="net461" />
<package id="System.IO.Pipelines" version="4.5.3" targetFramework="net461" />
<package id="System.Linq.Dynamic.Core" version="1.2.23" targetFramework="net461" />
<package id="System.Linq.Dynamic.Core" version="1.3.1" targetFramework="net461" />
<package id="System.Memory" version="4.5.4" targetFramework="net461" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net461" />
<package id="System.Reflection.Metadata" version="1.6.0" targetFramework="net461" />

View File

@@ -0,0 +1,43 @@
using Newtonsoft.Json;
using Testcontainers.MsSql;
using WireMock.Net.Testcontainers;
namespace WireMock.Net.TestcontainersExample;
internal class Program
{
private static async Task Main(string[] args)
{
var container = new WireMockContainerBuilder()
.WithAdminUserNameAndPassword("x", "y")
.WithMappings(@"C:\Dev\GitHub\WireMock.Net\examples\WireMock.Net.Console.NET6\__admin\mappings")
.WithWatchStaticMappings(true)
.WithAutoRemove(true)
.WithCleanUp(true)
.Build();
await container.StartAsync().ConfigureAwait(false);
var logs = await container.GetLogsAsync(DateTime.Now.AddDays(-1)).ConfigureAwait(false);
Console.WriteLine("logs = " + logs.Stdout);
var restEaseApiClient = container.CreateWireMockAdminClient();
var settings = await restEaseApiClient.GetSettingsAsync();
Console.WriteLine("settings = " + JsonConvert.SerializeObject(settings, Formatting.Indented));
var mappings = await restEaseApiClient.GetMappingsAsync();
Console.WriteLine("mappings = " + JsonConvert.SerializeObject(mappings, Formatting.Indented));
var client = container.CreateClient();
var result = await client.GetStringAsync("/static/mapping");
Console.WriteLine("result = " + result);
await container.StopAsync();
var sql = new MsSqlBuilder()
.WithAutoRemove(true)
.WithCleanUp(true)
.Build();
}
}

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Testcontainers.MsSql" Version="3.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="873d495f-940e-4b86-a1f4-4f0fc7be8b8b.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -12,13 +12,13 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0'">
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.9" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1'">
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.4" />
<PackageReference Include="Microsoft.AspNetCore.All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.8" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -39,14 +39,38 @@ public class MatcherModel
/// <summary>
/// The Operator to use when multiple patterns are defined. Optional.
/// - null = Same as "or".
/// - "or" = Only one pattern should match.
/// - "or" = Only one pattern is required to match.
/// - "and" = All patterns should match.
/// - "average" = The average value from all patterns.
/// </summary>
public string? MatchOperator { get; set; }
#region JsonPartialMatcher and JsonPartialWildcardMatcher
/// <summary>
/// Support Regex, only used for JsonPartialMatcher.
/// Support Regex.
/// </summary>
public bool? Regex { get; set; }
#endregion
#region MimePartMatcher
/// <summary>
/// ContentType Matcher (image/png; name=image.png)
/// </summary>
public MatcherModel? ContentTypeMatcher { get; set; }
/// <summary>
/// ContentDisposition Matcher (attachment; filename=image.png)
/// </summary>
public MatcherModel? ContentDispositionMatcher { get; set; }
/// <summary>
/// ContentTransferEncoding Matcher (base64)
/// </summary>
public MatcherModel? ContentTransferEncodingMatcher { get; set; }
/// <summary>
/// Content Matcher
/// </summary>
public MatcherModel? ContentMatcher { get; set; }
#endregion
}

View File

@@ -96,32 +96,39 @@ public interface IRequestMessage
/// <summary>
/// The original body as string. Convenience getter for Handlebars.
/// </summary>
string Body { get; }
string? Body { get; }
/// <summary>
/// The body (as JSON object). Convenience getter for Handlebars.
/// </summary>
object BodyAsJson { get; }
object? BodyAsJson { get; }
/// <summary>
/// The body (as bytearray). Convenience getter for Handlebars.
/// </summary>
byte[] BodyAsBytes { get; }
byte[]? BodyAsBytes { get; }
#if MIMEKIT
/// <summary>
/// The original body as MimeMessage. Convenience getter for Handlebars.
/// </summary>
object? BodyAsMimeMessage { get; }
#endif
/// <summary>
/// The detected body type. Convenience getter for Handlebars.
/// </summary>
string DetectedBodyType { get; }
string? DetectedBodyType { get; }
/// <summary>
/// The detected body type from the Content-Type header. Convenience getter for Handlebars.
/// </summary>
string DetectedBodyTypeFromContentType { get; }
string? DetectedBodyTypeFromContentType { get; }
/// <summary>
/// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
/// </summary>
string DetectedCompression { get; }
string? DetectedCompression { get; }
/// <summary>
/// Gets the Host
@@ -143,6 +150,14 @@ public interface IRequestMessage
/// </summary>
string Origin { get; }
/// <summary>
/// Get a query parameter.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
/// <returns>The query parameter value as WireMockList or null when not found.</returns>
WireMockList<string>? GetParameter(string key, bool ignoreCase = false);
#if NETSTANDARD1_3_OR_GREATER || NET461
/// <summary>
/// Gets the connection's client certificate

View File

@@ -30,6 +30,10 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1'" >
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />

View File

@@ -149,15 +149,15 @@ public class WireMockAssertions
using (new AssertionScope($"header \"{expectedKey}\" from requests sent with value(s)"))
{
var headerValues = _headers.First(h => h.Key == expectedKey).Value;
var matchingHeaderValues = _headers.Where(h => h.Key == expectedKey).SelectMany(h => h.Value.ToArray()).ToArray();
if (expectedValues.Length == 1)
{
headerValues.Should().Contain(expectedValues.First(), because, becauseArgs);
matchingHeaderValues.Should().Contain(expectedValues.First(), because, becauseArgs);
}
else
{
var trimmedHeaderValues = string.Join(",", headerValues.Select(x => x)).Split(',').Select(x => x.Trim()).ToList();
var trimmedHeaderValues = string.Join(",", matchingHeaderValues.Select(x => x)).Split(',').Select(x => x.Trim()).ToList();
foreach (var expectedValue in expectedValues)
{
trimmedHeaderValues.Should().Contain(expectedValue, because, becauseArgs);

View File

@@ -1,49 +1,49 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>FluentAssertions extensions for WireMock.Net</Description>
<AssemblyTitle>WireMock.Net.FluentAssertions</AssemblyTitle>
<Authors>Mahmoud Ali;Stef Heyenrath</Authors>
<TargetFrameworks>net451;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.FluentAssertions</AssemblyName>
<PackageId>WireMock.Net.FluentAssertions</PackageId>
<PackageTags>wiremock;FluentAssertions;UnitTest;Assert;Assertions</PackageTags>
<RootNamespace>WireMock.FluentAssertions</RootNamespace>
<ProjectGuid>{B6269AAC-170A-4346-8B9A-579DED3D9A95}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<LangVersion>10</LangVersion>
</PropertyGroup>
<PropertyGroup>
<Description>FluentAssertions extensions for WireMock.Net</Description>
<AssemblyTitle>WireMock.Net.FluentAssertions</AssemblyTitle>
<Authors>Mahmoud Ali;Stef Heyenrath</Authors>
<TargetFrameworks>net451;net47;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.FluentAssertions</AssemblyName>
<PackageId>WireMock.Net.FluentAssertions</PackageId>
<PackageTags>wiremock;FluentAssertions;UnitTest;Assert;Assertions</PackageTags>
<RootNamespace>WireMock.FluentAssertions</RootNamespace>
<ProjectGuid>{B6269AAC-170A-4346-8B9A-579DED3D9A95}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<!--<DelaySign>true</DelaySign>-->
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<LangVersion>10</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net451' or '$(TargetFramework)' == 'netstandard1.3'">
<PackageReference Include="FluentAssertions" Version="5.10.3" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net451' or '$(TargetFramework)' == 'netstandard1.3'">
<PackageReference Include="FluentAssertions" Version="5.10.3" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'netstandard1.3'">
<PackageReference Include="FluentAssertions" Version="6.5.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'netstandard1.3'">
<PackageReference Include="FluentAssertions" Version="6.5.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@@ -320,14 +320,14 @@ internal class OpenApiPathsMapper
var mappedHeaders = headers?.ToDictionary(
item => item.Key,
_ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern!
);
) ?? new Dictionary<string, object>();
if (!string.IsNullOrEmpty(responseContentType))
{
mappedHeaders.TryAdd(HeaderContentType, responseContentType!);
}
return mappedHeaders?.Keys.Any() == true ? mappedHeaders : null;
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
}
private IList<ParamModel>? MapQueryParameters(IEnumerable<OpenApiParameter> queryParameters)

View File

@@ -20,7 +20,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.2.3" />
<PackageReference Include="Nullable" Version="1.3.1">
<PrivateAssets>all</PrivateAssets>

View File

@@ -47,9 +47,9 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
/// <inheritdoc />
[PublicAPI]
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument openApiDocument, WireMockOpenApiParserSettings? settings = null)
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings? settings = null)
{
return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(openApiDocument.Paths, openApiDocument.Servers);
return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(document.Paths, document.Servers);
}
/// <inheritdoc />

View File

@@ -1,3 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
@@ -24,7 +25,7 @@ public static class StandAloneApp
[PublicAPI]
public static WireMockServer Start(WireMockServerSettings settings)
{
Guard.NotNull(settings, nameof(settings));
Guard.NotNull(settings);
var server = WireMockServer.Start(settings);
@@ -42,7 +43,7 @@ public static class StandAloneApp
[PublicAPI]
public static WireMockServer Start(string[] args, IWireMockLogger? logger = null)
{
Guard.NotNull(args, nameof(args));
Guard.NotNull(args);
if (TryStart(args, out var server, logger))
{
@@ -61,9 +62,9 @@ public static class StandAloneApp
[PublicAPI]
public static bool TryStart(string[] args, [NotNullWhen(true)] out WireMockServer? server, IWireMockLogger? logger = null)
{
Guard.NotNull(args, nameof(args));
Guard.NotNull(args);
if (WireMockServerSettingsParser.TryParseArguments(args, out var settings, logger))
if (WireMockServerSettingsParser.TryParseArguments(args, Environment.GetEnvironmentVariables(), out var settings, logger))
{
settings.Logger?.Info("Version [{0}]", Version);
settings.Logger?.Debug("Server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));

View File

@@ -0,0 +1,7 @@
namespace WireMock.Net.Testcontainers.Models;
internal record ContainerInfo
(
string Image,
string MappingsPath
);

View File

@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>A fluent testcontainer builder for the Docker version of WireMock.Net</Description>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>wiremock;docker;testcontainer;testcontainers</PackageTags>
<ProjectGuid>{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<LangVersion>10</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IsExternalInit" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
<PackageReference Include="Stef.Validation" Version="0.1.1" />
<PackageReference Include="Testcontainers" Version="3.2.0" />
<PackageReference Include="JetBrains.Annotations" VersionOverride="2022.3.1" PrivateAssets="All" Version="2022.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,66 @@
using Docker.DotNet.Models;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Configurations;
using JetBrains.Annotations;
namespace WireMock.Net.Testcontainers;
/// <inheritdoc cref="ContainerConfiguration" />
[PublicAPI]
public sealed class WireMockConfiguration : ContainerConfiguration
{
#pragma warning disable CS1591
public string? Username { get; }
public string? Password { get; }
public bool HasBasicAuthentication => !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password);
public WireMockConfiguration(
string? username = null,
string? password = null
)
{
Username = username;
Password = password;
}
#pragma warning restore CS1591
/// <summary>
/// Initializes a new instance of the <see cref="WireMockConfiguration" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
public WireMockConfiguration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration) : base(resourceConfiguration)
{
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
}
/// <summary>
/// Initializes a new instance of the <see cref="WireMockConfiguration" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
public WireMockConfiguration(IContainerConfiguration resourceConfiguration) : base(resourceConfiguration)
{
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
}
/// <summary>
/// Initializes a new instance of the <see cref="WireMockConfiguration" /> class.
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
public WireMockConfiguration(WireMockConfiguration resourceConfiguration) : this(new WireMockConfiguration(), resourceConfiguration)
{
// Passes the configuration upwards to the base implementations to create an updated immutable copy.
}
/// <summary>
/// Initializes a new instance of the <see cref="WireMockConfiguration" /> class.
/// </summary>
/// <param name="oldValue">The old Docker resource configuration.</param>
/// <param name="newValue">The new Docker resource configuration.</param>
public WireMockConfiguration(WireMockConfiguration oldValue, WireMockConfiguration newValue) : base(oldValue, newValue)
{
Username = BuildConfiguration.Combine(oldValue.Username, newValue.Username);
Password = BuildConfiguration.Combine(oldValue.Password, newValue.Password);
}
}

View File

@@ -0,0 +1,110 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using DotNet.Testcontainers.Containers;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using RestEase;
using Stef.Validation;
using WireMock.Client;
namespace WireMock.Net.Testcontainers;
/// <summary>
/// A container for running WireMock in a docker environment.
/// </summary>
public sealed class WireMockContainer : DockerContainer
{
internal const int ContainerPort = 80;
private readonly WireMockConfiguration _configuration;
/// <summary>
/// Initializes a new instance of the <see cref="WireMockContainer" /> class.
/// </summary>
/// <param name="configuration">The container configuration.</param>
/// <param name="logger">The logger.</param>
public WireMockContainer(WireMockConfiguration configuration, ILogger logger) : base(configuration, logger)
{
_configuration = Guard.NotNull(configuration);
}
/// <summary>
/// Gets the public Url.
/// </summary>
[PublicAPI]
public string GetPublicUrl() => GetPublicUri().ToString();
/// <summary>
/// Create a RestEase Admin client which can be used to call the admin REST endpoint.
/// </summary>
/// <returns>A <see cref="IWireMockAdminApi"/></returns>
[PublicAPI]
public IWireMockAdminApi CreateWireMockAdminClient()
{
ValidateIfRunning();
var api = RestClient.For<IWireMockAdminApi>(GetPublicUri());
if (_configuration.HasBasicAuthentication)
{
api.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{_configuration.Username}:{_configuration.Password}")));
}
return api;
}
/// <summary>
/// Create a <see cref="HttpClient"/> which can be used to call this instance.
/// <param name="handlers">
/// An ordered list of System.Net.Http.DelegatingHandler instances to be invoked
/// as an System.Net.Http.HttpRequestMessage travels from the System.Net.Http.HttpClient
/// to the network and an System.Net.Http.HttpResponseMessage travels from the network
/// back to System.Net.Http.HttpClient. The handlers are invoked in a top-down fashion.
/// That is, the first entry is invoked first for an outbound request message but
/// last for an inbound response message.
/// </param>
/// </summary>
[PublicAPI]
public HttpClient CreateClient(params DelegatingHandler[] handlers)
{
ValidateIfRunning();
var client = HttpClientFactory.Create(handlers);
client.BaseAddress = GetPublicUri();
return client;
}
/// <summary>
/// Create a <see cref="HttpClient"/> (one for each URL) which can be used to call this instance.
/// <param name="innerHandler">The inner handler represents the destination of the HTTP message channel.</param>
/// <param name="handlers">
/// An ordered list of System.Net.Http.DelegatingHandler instances to be invoked
/// as an System.Net.Http.HttpRequestMessage travels from the System.Net.Http.HttpClient
/// to the network and an System.Net.Http.HttpResponseMessage travels from the network
/// back to System.Net.Http.HttpClient. The handlers are invoked in a top-down fashion.
/// That is, the first entry is invoked first for an outbound request message but
/// last for an inbound response message.
/// </param>
/// </summary>
[PublicAPI]
public HttpClient CreateClient(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers)
{
ValidateIfRunning();
var client = HttpClientFactory.Create(innerHandler, handlers);
client.BaseAddress = GetPublicUri();
return client;
}
private void ValidateIfRunning()
{
if (State != TestcontainersStates.Running)
{
throw new InvalidOperationException("Unable to create HttpClient because the WireMock.Net is not yet running.");
}
}
private Uri GetPublicUri() => new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(ContainerPort)).Uri;
}

View File

@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Docker.DotNet.Models;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Configurations;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Net.Testcontainers.Models;
namespace WireMock.Net.Testcontainers;
/// <summary>
/// An specific fluent Docker container builder for WireMock.Net
/// </summary>
public sealed class WireMockContainerBuilder : ContainerBuilder<WireMockContainerBuilder, WireMockContainer, WireMockConfiguration>
{
private readonly Dictionary<bool, ContainerInfo> _info = new()
{
{ false, new ContainerInfo("sheyenrath/wiremock.net:latest", "/app/__admin/mappings") },
{ true, new ContainerInfo("sheyenrath/wiremock.net-windows:latest", @"c:\app\__admin\mappings") }
};
private const string DefaultLogger = "WireMockConsoleLogger";
private readonly Lazy<Task<bool>> _isWindowsAsLazy = new(async () =>
{
using var dockerClientConfig = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration();
using var dockerClient = dockerClientConfig.CreateClient();
var version = await dockerClient.System.GetVersionAsync();
return version.Os.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) > -1;
});
/// <summary>
/// Initializes a new instance of the <see cref="ContainerBuilder" /> class.
/// </summary>
public WireMockContainerBuilder() : this(new WireMockConfiguration())
{
DockerResourceConfiguration = Init().DockerResourceConfiguration;
}
/// <summary>
/// Automatically set the correct image (Linux or Windows) for WireMock which to create the container.
/// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI]
public WireMockContainerBuilder WithImage()
{
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
return WithImage(_info[isWindows].Image);
}
/// <summary>
/// Set the admin username and password for the container (basic authentication).
/// </summary>
/// <param name="username">The admin username.</param>
/// <param name="password">The admin password.</param>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
public WireMockContainerBuilder WithAdminUserNameAndPassword(string username, string password)
{
Guard.NotNull(username);
Guard.NotNull(password);
if (string.IsNullOrEmpty(username) && string.IsNullOrEmpty(password))
{
return this;
}
return Merge(DockerResourceConfiguration, new WireMockConfiguration(username, password))
.WithCommand($"--AdminUserName {username}", $"--AdminPassword {password}");
}
/// <summary>
/// Use the WireMockNullLogger.
/// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI]
public WireMockContainerBuilder WithNullLogger()
{
return WithCommand("--WireMockLogger WireMockNullLogger");
}
/// <summary>
/// Defines if the static mappings should be read at startup (default set to false).
/// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI]
public WireMockContainerBuilder WithReadStaticMappings()
{
return WithCommand("--ReadStaticMappings true");
}
/// <summary>
/// Watch the static mapping files + folder for changes when running.
/// </summary>
/// <returns>A configured instance of <see cref="WireMockContainerBuilder"/></returns>
[PublicAPI]
public WireMockContainerBuilder WithWatchStaticMappings(bool includeSubDirectories)
{
return WithCommand("--WatchStaticMappings true").WithCommand($"--WatchStaticMappingsInSubdirectories {includeSubDirectories}");
}
/// <summary>
/// Specifies the path for the (static) mapping json files.
/// </summary>
/// <param name="path">The path</param>
/// <returns></returns>
[PublicAPI]
public WireMockContainerBuilder WithMappings(string path)
{
Guard.NotNullOrEmpty(path);
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
return WithReadStaticMappings().WithBindMount(path, _info[isWindows].MappingsPath);
}
/// <summary>
/// Initializes a new instance of the <see cref="WireMockContainerBuilder" /> class.
/// </summary>
/// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
private WireMockContainerBuilder(WireMockConfiguration dockerResourceConfiguration) : base(dockerResourceConfiguration)
{
DockerResourceConfiguration = dockerResourceConfiguration;
}
/// <inheritdoc />
protected override WireMockConfiguration DockerResourceConfiguration { get; }
/// <inheritdoc />
public override WireMockContainer Build()
{
Validate();
return new WireMockContainer(DockerResourceConfiguration, TestcontainersSettings.Logger);
}
/// <inheritdoc />
protected override WireMockContainerBuilder Init()
{
var builder = base.Init();
// In case no image has been set, set the image using internal logic.
if (builder.DockerResourceConfiguration.Image == null)
{
builder = builder.WithImage();
}
var isWindows = _isWindowsAsLazy.Value.GetAwaiter().GetResult();
var waitForContainerOS = isWindows ? Wait.ForWindowsContainer() : Wait.ForUnixContainer();
return builder
.WithPortBinding(WireMockContainer.ContainerPort, true)
.WithCommand($"--WireMockLogger {DefaultLogger}")
.WithWaitStrategy(waitForContainerOS.UntilMessageIsLogged("By Stef Heyenrath"));
}
/// <inheritdoc />
protected override WireMockContainerBuilder Clone(IContainerConfiguration resourceConfiguration)
{
return Merge(DockerResourceConfiguration, new WireMockConfiguration(resourceConfiguration));
}
/// <inheritdoc />
protected override WireMockContainerBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
{
return Merge(DockerResourceConfiguration, new WireMockConfiguration(resourceConfiguration));
}
/// <inheritdoc />
protected override WireMockContainerBuilder Merge(WireMockConfiguration oldValue, WireMockConfiguration newValue)
{
return new WireMockContainerBuilder(new WireMockConfiguration(oldValue, newValue));
}
}

View File

@@ -26,7 +26,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Stef.Validation" Version="0.1.1" />
<PackageReference Include="xUnit.abstractions" Version="2.0.3" />
</ItemGroup>

View File

@@ -0,0 +1,17 @@
{
"help": "https://go.microsoft.com/fwlink/?linkid=866610",
"root": true,
"dependentFileProviders": {
"add": {
"addedExtension": {},
"pathSegment": {
"add": {
".*": [
".cs"
]
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using Stef.Validation;
namespace WireMock.Extensions;
internal static class DictionaryExtensions
{
public static bool TryGetStringValue(this IDictionary dictionary, string key, [NotNullWhen(true)] out string? value)
{
Guard.NotNull(dictionary);
if (dictionary[key] is string valueIsString)
{
value = valueIsString;
return true;
}
var valueToString = dictionary[key]?.ToString();
if (valueToString != null)
{
value = valueToString;
return true;
}
value = default;
return false;
}
}

View File

@@ -5,12 +5,18 @@ using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Stef.Validation;
using WireMock.Constants;
using WireMock.Types;
namespace WireMock.Http;
internal static class HttpRequestMessageHelper
{
private static readonly IDictionary<string, bool> ContentLengthHeaderAllowed = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase)
{
{ HttpRequestMethod.HEAD, true }
};
internal static HttpRequestMessage Create(IRequestMessage requestMessage, string url)
{
Guard.NotNull(requestMessage);
@@ -25,21 +31,14 @@ internal static class HttpRequestMessageHelper
MediaTypeHeaderValue.TryParse(value, out contentType);
}
switch (requestMessage.BodyData?.DetectedBodyType)
httpRequestMessage.Content = requestMessage.BodyData?.DetectedBodyType switch
{
case BodyType.Bytes:
httpRequestMessage.Content = ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes!, contentType);
break;
case BodyType.Json:
httpRequestMessage.Content = StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType);
break;
case BodyType.String:
case BodyType.FormUrlEncoded:
httpRequestMessage.Content = StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType);
break;
}
BodyType.Bytes => ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes!, contentType),
BodyType.Json => StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType),
BodyType.String => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType),
BodyType.FormUrlEncoded => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType),
_ => httpRequestMessage.Content
};
// Overwrite the host header
httpRequestMessage.Headers.Host = new Uri(url).Authority;
@@ -50,7 +49,19 @@ internal static class HttpRequestMessageHelper
return httpRequestMessage;
}
var excludeHeaders = new List<string> { HttpKnownHeaderNames.Host, HttpKnownHeaderNames.ContentLength };
var excludeHeaders = new List<string> { HttpKnownHeaderNames.Host };
var contentLengthHeaderAllowed = ContentLengthHeaderAllowed.TryGetValue(requestMessage.Method, out var allowed) && allowed;
if (contentLengthHeaderAllowed)
{
// Set Content to empty ByteArray to be able to set the Content-Length on the content in case of a HEAD method.
httpRequestMessage.Content ??= new ByteArrayContent(EmptyArray<byte>.Value);
}
else
{
excludeHeaders.Add(HttpKnownHeaderNames.ContentLength);
}
if (contentType != null)
{
// Content-Type should be set on the content

View File

@@ -74,6 +74,13 @@ public abstract class AbstractJsonPartialMatcher : JsonMatcher
}
}
if (input != null &&
((value.Type == JTokenType.Guid && input.Type == JTokenType.String) ||
(value.Type == JTokenType.String && input.Type == JTokenType.Guid)))
{
return IsMatch(value.ToString(), input.ToString());
}
if (input == null || value.Type != input.Type)
{
return false;

View File

@@ -0,0 +1,139 @@
#if GRAPHQL
using System;
using System.Collections.Generic;
using System.Linq;
using AnyOfTypes;
using GraphQL;
using GraphQL.Types;
using Newtonsoft.Json;
using Stef.Validation;
using WireMock.Models;
namespace WireMock.Matchers;
/// <summary>
/// GrapQLMatcher Schema Matcher
/// </summary>
/// <inheritdoc cref="IStringMatcher"/>
public class GraphQLMatcher : IStringMatcher
{
private sealed class GraphQLRequest
{
public string? Query { get; set; }
public Dictionary<string, object?>? Variables { get; set; }
}
private readonly AnyOf<string, StringPattern>[] _patterns;
private readonly ISchema _schema;
/// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc />
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary>
/// <param name="schema">The schema.</param>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
public GraphQLMatcher(AnyOf<string, StringPattern, ISchema> schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, bool throwException = false, MatchOperator matchOperator = MatchOperator.Or)
{
Guard.NotNull(schema);
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator;
var patterns = new List<AnyOf<string, StringPattern>>();
switch (schema.CurrentType)
{
case AnyOfType.First:
patterns.Add(schema.First);
_schema = BuildSchema(schema);
break;
case AnyOfType.Second:
patterns.Add(schema.Second);
_schema = BuildSchema(schema.Second.Pattern);
break;
case AnyOfType.Third:
_schema = schema.Third;
break;
default:
throw new NotSupportedException();
}
_patterns = patterns.ToArray();
}
/// <inheritdoc />
public double IsMatch(string? input)
{
var match = MatchScores.Mismatch;
try
{
var graphQLRequest = JsonConvert.DeserializeObject<GraphQLRequest>(input!)!;
var executionResult = new DocumentExecuter().ExecuteAsync(_ =>
{
_.ThrowOnUnhandledException = true;
_.Schema = _schema;
_.Query = graphQLRequest.Query;
if (graphQLRequest.Variables != null)
{
_.Variables = new Inputs(graphQLRequest.Variables);
}
}).GetAwaiter().GetResult();
if (executionResult.Errors == null || executionResult.Errors.Count == 0)
{
match = MatchScores.Perfect;
}
else
{
var exceptions = executionResult.Errors.OfType<Exception>().ToArray();
if (exceptions.Length == 1)
{
throw exceptions[0];
}
throw new AggregateException(exceptions);
}
}
catch
{
if (ThrowException)
{
throw;
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public string Name => nameof(GraphQLMatcher);
private static ISchema BuildSchema(string schema)
{
return Schema.For(schema);
}
}
#endif

View File

@@ -0,0 +1,78 @@
using Stef.Validation;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.Matchers.Helpers;
internal static class BodyDataMatchScoreCalculator
{
public static double CalculateMatchScore(IBodyData? requestMessage, IMatcher matcher)
{
Guard.NotNull(matcher);
if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
{
switch (requestMessage?.DetectedBodyType)
{
case BodyType.Json:
case BodyType.String:
case BodyType.FormUrlEncoded:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsString);
case BodyType.Bytes:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsBytes);
default:
return MatchScores.Mismatch;
}
}
if (matcher is ExactObjectMatcher exactObjectMatcher)
{
// If the body is a byte array, try to match.
var detectedBodyType = requestMessage?.DetectedBodyType;
if (detectedBodyType is BodyType.Bytes or BodyType.String or BodyType.FormUrlEncoded)
{
return exactObjectMatcher.IsMatch(requestMessage?.BodyAsBytes);
}
}
// Check if the matcher is a IObjectMatcher
if (matcher is IObjectMatcher objectMatcher)
{
// If the body is a JSON object, try to match.
if (requestMessage?.DetectedBodyType == BodyType.Json)
{
return objectMatcher.IsMatch(requestMessage.BodyAsJson);
}
// If the body is a byte array, try to match.
if (requestMessage?.DetectedBodyType == BodyType.Bytes)
{
return objectMatcher.IsMatch(requestMessage.BodyAsBytes);
}
}
// Check if the matcher is a IStringMatcher
if (matcher is IStringMatcher stringMatcher)
{
// If the body is a Json or a String, use the BodyAsString to match on.
if (requestMessage?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
{
return stringMatcher.IsMatch(requestMessage.BodyAsString);
}
}
#if MIMEKIT_XXX
if (matcher is MultiPartMatcher multiPartMatcher)
{
// If the body is a String or MultiPart, use the BodyAsString to match on.
if (requestMessage?.DetectedBodyType is BodyType.String or BodyType.MultiPart)
{
return multiPartMatcher.IsMatch(requestMessage.BodyAsString);
}
}
#endif
return MatchScores.Mismatch;
}
}

View File

@@ -121,6 +121,34 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
private double IsMatch(JToken jToken)
{
return MatchScores.ToScore(_patterns.Select(pattern => jToken.SelectToken(pattern.GetPattern()) != null).ToArray(), MatchOperator);
var array = ConvertJTokenToJArrayIfNeeded(jToken);
// The SelectToken method can accept a string path to a child token ( i.e. "Manufacturers[0].Products[0].Price").
// In that case it will return a JValue (some type) which does not implement the IEnumerable interface.
return MatchScores.ToScore(_patterns.Select(pattern => array.SelectToken(pattern.GetPattern()) != null).ToArray(), MatchOperator);
}
}
// https://github.com/WireMock-Net/WireMock.Net/issues/965
// https://stackoverflow.com/questions/66922188/newtonsoft-jsonpath-with-c-sharp-syntax
// Filtering using SelectToken() isn't guaranteed to work for objects inside objects -- only objects inside arrays.
// So this code checks if it's an JArray, if it's not an array, construct a new JArray.
private static JToken ConvertJTokenToJArrayIfNeeded(JToken jToken)
{
if (jToken.Count() == 1)
{
var property = jToken.First();
var item = property.First();
if (item is JArray)
{
return jToken;
}
return new JObject
{
[property.Path] = new JArray(item)
};
}
return jToken;
}
}

View File

@@ -1,4 +1,3 @@
using System;
using System.Linq;
using System.Linq.Dynamic.Core;
using AnyOfTypes;
@@ -69,7 +68,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
MatchOperator = matchOperator;
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
/// <inheritdoc />
public double IsMatch(string? input)
{
double match = MatchScores.Mismatch;
@@ -95,7 +94,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
/// <inheritdoc />
public double IsMatch(object? input)
{
double match = MatchScores.Mismatch;
@@ -110,45 +109,19 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
jArray = new JArray { JToken.FromObject(input) };
}
//enumerable = jArray.ToDynamicClassArray();
//JObject value;
//switch (input)
//{
// case JObject valueAsJObject:
// value = valueAsJObject;
// break;
// case { } valueAsObject:
// value = JObject.FromObject(valueAsObject);
// break;
// default:
// return MatchScores.Mismatch;
//}
// Convert a single object to a Queryable JObject-list with 1 entry.
//var queryable1 = new[] { value }.AsQueryable();
var queryable = jArray.ToDynamicClassArray().AsQueryable();
try
{
// Generate the DynamicLinq select statement.
//string dynamicSelect = JsonUtils.GenerateDynamicLinqStatement(value);
// Execute DynamicLinq Select statement.
//var queryable2 = queryable1.Select(dynamicSelect);
// Use the Any(...) method to check if the result matches.
var patternsAsStringArray = _patterns.Select(p => p.GetPattern()).ToArray();
var scores = patternsAsStringArray.Select(p => queryable.Any(p)).ToArray();
match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern.GetPattern())).ToArray(), MatchOperator);
match = MatchScores.ToScore(scores, MatchOperator);
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
catch (Exception e)
catch
{
if (ThrowException)
{
@@ -159,7 +132,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
/// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
@@ -168,6 +141,6 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/>
/// <inheritdoc />
public string Name => "LinqMatcher";
}

View File

@@ -1,7 +1,7 @@
namespace WireMock.Matchers;
/// <summary>
/// MatchBehaviour
/// MatchBehaviour (Accept or Reject)
/// </summary>
public enum MatchBehaviour
{

View File

@@ -0,0 +1,125 @@
#if MIMEKIT
using System;
using MimeKit;
using WireMock.Matchers.Helpers;
using WireMock.Util;
namespace WireMock.Matchers;
/// <summary>
/// MimePartMatcher
/// </summary>
public class MimePartMatcher : IMatcher
{
private readonly Func<MimePart, double>[] _funcs;
/// <inheritdoc />
public string Name => nameof(MimePartMatcher);
/// <summary>
/// ContentType Matcher (image/png; name=image.png.)
/// </summary>
public IStringMatcher? ContentTypeMatcher { get; }
/// <summary>
/// ContentDisposition Matcher (attachment; filename=image.png)
/// </summary>
public IStringMatcher? ContentDispositionMatcher { get; }
/// <summary>
/// ContentTransferEncoding Matcher (base64)
/// </summary>
public IStringMatcher? ContentTransferEncodingMatcher { get; }
/// <summary>
/// Content Matcher
/// </summary>
public IMatcher? ContentMatcher { get; }
/// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc />
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MimePartMatcher"/> class.
/// </summary>
public MimePartMatcher(
MatchBehaviour matchBehaviour,
IStringMatcher? contentTypeMatcher,
IStringMatcher? contentDispositionMatcher,
IStringMatcher? contentTransferEncodingMatcher,
IMatcher? contentMatcher,
bool throwException = false
)
{
MatchBehaviour = matchBehaviour;
ContentTypeMatcher = contentTypeMatcher;
ContentDispositionMatcher = contentDispositionMatcher;
ContentTransferEncodingMatcher = contentTransferEncodingMatcher;
ContentMatcher = contentMatcher;
ThrowException = throwException;
_funcs = new[]
{
mp => ContentTypeMatcher?.IsMatch(GetContentTypeAsString(mp.ContentType)) ?? MatchScores.Perfect,
mp => ContentDispositionMatcher?.IsMatch(mp.ContentDisposition.ToString().Replace("Content-Disposition: ", string.Empty)) ?? MatchScores.Perfect,
mp => ContentTransferEncodingMatcher?.IsMatch(mp.ContentTransferEncoding.ToString().ToLowerInvariant()) ?? MatchScores.Perfect,
MatchOnContent
};
}
/// <summary>
/// Determines whether the specified MimePart is match.
/// </summary>
/// <param name="mimePart">The MimePart.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
public double IsMatch(MimePart mimePart)
{
var match = MatchScores.Mismatch;
try
{
if (Array.TrueForAll(_funcs, func => MatchScores.IsPerfect(func(mimePart))))
{
match = MatchScores.Perfect;
}
}
catch
{
if (ThrowException)
{
throw;
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
private double MatchOnContent(MimePart mimePart)
{
if (ContentMatcher == null)
{
return MatchScores.Perfect;
}
var bodyParserSettings = new BodyParserSettings
{
Stream = mimePart.Content.Open(),
ContentType = GetContentTypeAsString(mimePart.ContentType),
DeserializeJson = true,
ContentEncoding = null, // mimePart.ContentType.CharsetEncoding.ToString(),
DecompressGZipAndDeflate = true
};
var bodyData = BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false).GetAwaiter().GetResult();
return BodyDataMatchScoreCalculator.CalculateMatchScore(bodyData, ContentMatcher);
}
private static string? GetContentTypeAsString(ContentType? contentType)
{
return contentType?.ToString().Replace("Content-Type: ", string.Empty);
}
}
#endif

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Stef.Validation;
using WireMock.Types;
using WireMock.Matchers.Helpers;
using WireMock.Util;
namespace WireMock.Matchers.Request;
@@ -149,69 +149,11 @@ public class RequestMessageBodyMatcher : IRequestMatcher
return requestMatchResult.AddScore(GetType(), score);
}
private static double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
{
if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
{
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Json:
case BodyType.String:
case BodyType.FormUrlEncoded:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
case BodyType.Bytes:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
default:
return MatchScores.Mismatch;
}
}
if (matcher is ExactObjectMatcher exactObjectMatcher)
{
// If the body is a byte array, try to match.
var detectedBodyType = requestMessage.BodyData?.DetectedBodyType;
if (detectedBodyType is BodyType.Bytes or BodyType.String or BodyType.FormUrlEncoded)
{
return exactObjectMatcher.IsMatch(requestMessage.BodyData?.BodyAsBytes);
}
}
// Check if the matcher is a IObjectMatcher
if (matcher is IObjectMatcher objectMatcher)
{
// If the body is a JSON object, try to match.
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
{
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsJson);
}
// If the body is a byte array, try to match.
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Bytes)
{
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
}
}
// Check if the matcher is a IStringMatcher
if (matcher is IStringMatcher stringMatcher)
{
// If the body is a Json or a String, use the BodyAsString to match on.
if (requestMessage?.BodyData?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
{
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
}
}
return MatchScores.Mismatch;
}
private double CalculateMatchScore(IRequestMessage requestMessage)
{
if (Matchers != null)
{
var matchersResult = Matchers.Select(matcher => CalculateMatchScore(requestMessage, matcher)).ToArray();
var matchersResult = Matchers.Select(matcher => BodyDataMatchScoreCalculator.CalculateMatchScore(requestMessage.BodyData, matcher)).ToArray();
return MatchScores.ToScore(matchersResult, MatchOperator);
}

View File

@@ -0,0 +1,105 @@
using System.Linq;
using Stef.Validation;
using WireMock.Types;
namespace WireMock.Matchers.Request;
/// <summary>
/// The request body GraphQL matcher.
/// </summary>
public class RequestMessageGraphQLMatcher : IRequestMatcher
{
/// <summary>
/// The matchers.
/// </summary>
public IMatcher[]? Matchers { get; }
/// <summary>
/// The <see cref="MatchOperator"/>
/// </summary>
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="schema">The schema.</param>
public RequestMessageGraphQLMatcher(MatchBehaviour matchBehaviour, string schema) :
this(CreateMatcherArray(matchBehaviour, schema))
{
}
#if GRAPHQL
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="schema">The schema.</param>
public RequestMessageGraphQLMatcher(MatchBehaviour matchBehaviour, GraphQL.Types.ISchema schema) :
this(CreateMatcherArray(matchBehaviour, new AnyOfTypes.AnyOf<string, Models.StringPattern, GraphQL.Types.ISchema>(schema)))
{
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessageGraphQLMatcher(params IMatcher[] matchers)
{
Matchers = Guard.NotNull(matchers);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
public RequestMessageGraphQLMatcher(MatchOperator matchOperator, params IMatcher[] matchers)
{
Matchers = Guard.NotNull(matchers);
MatchOperator = matchOperator;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
var score = CalculateMatchScore(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private static double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
{
// Check if the matcher is a IStringMatcher
// If the body is a Json or a String, use the BodyAsString to match on.
if (matcher is IStringMatcher stringMatcher && requestMessage.BodyData?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
{
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
}
return MatchScores.Mismatch;
}
private double CalculateMatchScore(IRequestMessage requestMessage)
{
if (Matchers == null)
{
return MatchScores.Mismatch;
}
var matchersResult = Matchers.Select(matcher => CalculateMatchScore(requestMessage, matcher)).ToArray();
return MatchScores.ToScore(matchersResult, MatchOperator);
}
#if GRAPHQL
private static IMatcher[] CreateMatcherArray(MatchBehaviour matchBehaviour, AnyOfTypes.AnyOf<string, Models.StringPattern, GraphQL.Types.ISchema> schema)
{
return new[] { new GraphQLMatcher(schema, matchBehaviour) }.Cast<IMatcher>().ToArray();
}
#else
private static IMatcher[] CreateMatcherArray(MatchBehaviour matchBehaviour, object schema)
{
throw new System.NotSupportedException("The GrapQLMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
}
#endif
}

View File

@@ -0,0 +1,99 @@
using System.Collections.Generic;
using System.Linq;
using Stef.Validation;
using WireMock.Http;
using WireMock.Util;
namespace WireMock.Matchers.Request;
/// <summary>
/// The request body MultiPart matcher.
/// </summary>
public class RequestMessageMultiPartMatcher : IRequestMatcher
{
/// <summary>
/// The matchers.
/// </summary>
public IMatcher[]? Matchers { get; }
/// <summary>
/// The <see cref="MatchOperator"/>
/// </summary>
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
/// <summary>
/// The <see cref="MatchBehaviour"/>
/// </summary>
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageMultiPartMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessageMultiPartMatcher(params IMatcher[] matchers)
{
Matchers = Guard.NotNull(matchers);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageMultiPartMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
/// <param name="matchers">The matchers.</param>
public RequestMessageMultiPartMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator, params IMatcher[] matchers)
{
Matchers = Guard.NotNull(matchers);
MatchBehaviour = matchBehaviour;
MatchOperator = matchOperator;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
#if !MIMEKIT
throw new System.NotSupportedException("The MultiPartMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
#else
var match = MatchScores.Mismatch;
if (Matchers?.Any() != true)
{
return requestMatchResult.AddScore(GetType(), match);
}
try
{
var message = MimeKitUtils.GetMimeMessage(requestMessage.BodyData!, requestMessage.Headers![HttpKnownHeaderNames.ContentType].ToString());
var mimePartMatchers = Matchers.OfType<MimePartMatcher>().ToArray();
foreach (var mimePart in message.BodyParts.OfType<MimeKit.MimePart>())
{
var matchesForMimePart = new List<double> { MatchScores.Mismatch };
matchesForMimePart.AddRange(mimePartMatchers.Select(matcher => matcher.IsMatch(mimePart)));
match = matchesForMimePart.Max();
if (MatchScores.IsPerfect(match))
{
if (MatchOperator == MatchOperator.Or)
{
break;
}
}
else
{
match = MatchScores.Mismatch;
break;
}
}
}
catch
{
// Empty
}
return requestMatchResult.AddScore(GetType(), match);
#endif
}
}

View File

@@ -29,17 +29,13 @@ namespace WireMock.Owin.Mappers
var headers = new Dictionary<string, string[]>();
IEnumerable<string>? contentEncodingHeader = null;
if (request.Headers.Any())
foreach (var header in request.Headers)
{
headers = new Dictionary<string, string[]>();
foreach (var header in request.Headers)
{
headers.Add(header.Key, header.Value);
headers.Add(header.Key, header.Value!);
if (string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase))
{
contentEncodingHeader = header.Value;
}
if (string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase))
{
contentEncodingHeader = header.Value;
}
}

View File

@@ -60,7 +60,7 @@ namespace WireMock.Owin
public Task Invoke(IContext ctx)
#endif
{
if (_options.HandleRequestsSynchronously.GetValueOrDefault(true))
if (_options.HandleRequestsSynchronously.GetValueOrDefault(false))
{
lock (_lock)
{
@@ -216,7 +216,12 @@ namespace WireMock.Owin
{
try
{
await webhookSender.SendAsync(httpClientForWebhook, mapping, webhookRequest, request, response).ConfigureAwait(false);
var result = await webhookSender.SendAsync(httpClientForWebhook, mapping, webhookRequest, request, response).ConfigureAwait(false);
if (!result.IsSuccessStatusCode)
{
var content = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
_options.Logger.Warn($"Sending message to Webhook [{webHookIndex}] from Mapping '{mapping.Guid}' failed. HttpStatusCode: {result.StatusCode} Content: {content}");
}
}
catch (Exception ex)
{

View File

@@ -10,7 +10,7 @@ namespace WireMock.RequestBuilders;
/// <summary>
/// The BodyRequestBuilder interface.
/// </summary>
public interface IBodyRequestBuilder : IRequestMatcher
public interface IBodyRequestBuilder : IGraphQLRequestBuilder
{
/// <summary>
/// WithBody: IMatcher
@@ -103,4 +103,12 @@ public interface IBodyRequestBuilder : IRequestMatcher
/// <param name="func">The form-urlencoded values.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBody(Func<IDictionary<string, string>?, bool> func);
/// <summary>
/// WithBodyAsGraphQLSchema: Body as GraphQL schema as a string.
/// </summary>
/// <param name="body">The GraphQL schema.</param>
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithBodyAsGraphQLSchema(string body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
}

View File

@@ -0,0 +1,27 @@
using WireMock.Matchers;
namespace WireMock.RequestBuilders;
/// <summary>
/// The GraphQLRequestBuilder interface.
/// </summary>
public interface IGraphQLRequestBuilder : IMultiPartRequestBuilder
{
/// <summary>
/// WithGraphQLSchema: The GraphQL schema as a string.
/// </summary>
/// <param name="schema">The GraphQL schema.</param>
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithGraphQLSchema(string schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
#if GRAPHQL
/// <summary>
/// WithGraphQLSchema: The GraphQL schema as a ISchema.
/// </summary>
/// <param name="schema">The GraphQL schema.</param>
/// <param name="matchBehaviour">The match behaviour. (Default is <c>MatchBehaviour.AcceptOnMatch</c>).</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch);
#endif
}

View File

@@ -1,5 +1,3 @@
using System;
using JetBrains.Annotations;
using WireMock.Matchers;
namespace WireMock.RequestBuilders;

View File

@@ -0,0 +1,34 @@
using WireMock.Matchers;
using WireMock.Matchers.Request;
namespace WireMock.RequestBuilders;
/// <summary>
/// The MultiPartRequestBuilder interface.
/// </summary>
public interface IMultiPartRequestBuilder : IRequestMatcher
{
/// <summary>
/// WithMultiPart: IMatcher
/// </summary>
/// <param name="matcher">The matcher.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithMultiPart(IMatcher matcher);
/// <summary>
/// WithMultiPart: IMatcher[], MatchBehaviour and MatchOperator
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <param name="matchBehaviour">The <see cref="MatchBehaviour"/> to use.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithMultiPart(IMatcher[] matchers, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, MatchOperator matchOperator = MatchOperator.Or);
/// <summary>
/// WithMultiPart: MatchBehaviour and IMatcher[]
/// </summary>
/// <param name="matchBehaviour">The <see cref="MatchBehaviour"/> to use.</param>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
IRequestBuilder WithMultiPart(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, params IMatcher[] matchers);
}

View File

@@ -109,4 +109,10 @@ public partial class Request
_requestMatchers.Add(new RequestMessageBodyMatcher(Guard.NotNull(func)));
return this;
}
/// <inheritdoc />
public IRequestBuilder WithBodyAsGraphQLSchema(string body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
return WithGraphQLSchema(body, matchBehaviour);
}
}

View File

@@ -0,0 +1,23 @@
using WireMock.Matchers;
using WireMock.Matchers.Request;
namespace WireMock.RequestBuilders;
public partial class Request
{
/// <inheritdoc />
public IRequestBuilder WithGraphQLSchema(string schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageGraphQLMatcher(matchBehaviour, schema));
return this;
}
#if GRAPHQL
/// <inheritdoc />
public IRequestBuilder WithGraphQLSchema(GraphQL.Types.ISchema schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
_requestMatchers.Add(new RequestMessageGraphQLMatcher(matchBehaviour, schema));
return this;
}
#endif
}

View File

@@ -0,0 +1,28 @@
using WireMock.Matchers;
using WireMock.Matchers.Request;
namespace WireMock.RequestBuilders;
public partial class Request
{
/// <inheritdoc />
public IRequestBuilder WithMultiPart(IMatcher matcher)
{
_requestMatchers.Add(new RequestMessageMultiPartMatcher(matcher));
return this;
}
/// <inheritdoc />
public IRequestBuilder WithMultiPart(IMatcher[] matchers, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, MatchOperator matchOperator = MatchOperator.Or)
{
_requestMatchers.Add(new RequestMessageMultiPartMatcher(matchBehaviour, matchOperator, matchers));
return this;
}
/// <inheritdoc />
public IRequestBuilder WithMultiPart(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, params IMatcher[] matchers)
{
_requestMatchers.Add(new RequestMessageMultiPartMatcher(matchBehaviour, MatchOperator.Or, matchers));
return this;
}
}

View File

@@ -8,6 +8,7 @@ using System.Net;
using System.Security.Cryptography.X509Certificates;
#endif
using Stef.Validation;
using WireMock.Http;
using WireMock.Models;
using WireMock.Owin;
using WireMock.Types;
@@ -20,40 +21,40 @@ namespace WireMock;
/// </summary>
public class RequestMessage : IRequestMessage
{
/// <inheritdoc cref="IRequestMessage.ClientIP" />
/// <inheritdoc />
public string ClientIP { get; }
/// <inheritdoc cref="IRequestMessage.Url" />
/// <inheritdoc />
public string Url { get; }
/// <inheritdoc cref="IRequestMessage.AbsoluteUrl" />
/// <inheritdoc />
public string AbsoluteUrl { get; }
/// <inheritdoc cref="IRequestMessage.ProxyUrl" />
/// <inheritdoc />
public string? ProxyUrl { get; set; }
/// <inheritdoc cref="IRequestMessage.DateTime" />
/// <inheritdoc />
public DateTime DateTime { get; set; }
/// <inheritdoc cref="IRequestMessage.Path" />
/// <inheritdoc />
public string Path { get; }
/// <inheritdoc cref="IRequestMessage.AbsolutePath" />
/// <inheritdoc />
public string AbsolutePath { get; }
/// <inheritdoc cref="IRequestMessage.PathSegments" />
/// <inheritdoc />
public string[] PathSegments { get; }
/// <inheritdoc cref="IRequestMessage.AbsolutePathSegments" />
/// <inheritdoc />
public string[] AbsolutePathSegments { get; }
/// <inheritdoc cref="IRequestMessage.Method" />
/// <inheritdoc />
public string Method { get; }
/// <inheritdoc cref="IRequestMessage.Headers" />
/// <inheritdoc />
public IDictionary<string, WireMockList<string>>? Headers { get; }
/// <inheritdoc cref="IRequestMessage.Cookies" />
/// <inheritdoc />
public IDictionary<string, string>? Cookies { get; }
/// <inheritdoc />
@@ -61,45 +62,50 @@ public class RequestMessage : IRequestMessage
/// <inheritdoc />
public IDictionary<string, WireMockList<string>>? QueryIgnoreCase { get; }
/// <inheritdoc cref="IRequestMessage.RawQuery" />
/// <inheritdoc />
public string RawQuery { get; }
/// <inheritdoc cref="IRequestMessage.BodyData" />
/// <inheritdoc />
public IBodyData? BodyData { get; }
/// <inheritdoc cref="IRequestMessage.Body" />
public string Body { get; }
/// <inheritdoc />
public string? Body { get; }
/// <inheritdoc cref="IRequestMessage.BodyAsJson" />
public object BodyAsJson { get; }
/// <inheritdoc />
public object? BodyAsJson { get; }
/// <inheritdoc cref="IRequestMessage.BodyAsBytes" />
public byte[] BodyAsBytes { get; }
/// <inheritdoc />
public byte[]? BodyAsBytes { get; }
/// <inheritdoc cref="IRequestMessage.DetectedBodyType" />
public string DetectedBodyType { get; }
#if MIMEKIT
/// <inheritdoc />
public object? BodyAsMimeMessage { get; }
#endif
/// <inheritdoc cref="IRequestMessage.DetectedBodyTypeFromContentType" />
public string DetectedBodyTypeFromContentType { get; }
/// <inheritdoc />
public string? DetectedBodyType { get; }
/// <inheritdoc cref="IRequestMessage.DetectedCompression" />
public string DetectedCompression { get; }
/// <inheritdoc />
public string? DetectedBodyTypeFromContentType { get; }
/// <inheritdoc cref="IRequestMessage.Host" />
/// <inheritdoc />
public string? DetectedCompression { get; }
/// <inheritdoc />
public string Host { get; }
/// <inheritdoc cref="IRequestMessage.Protocol" />
/// <inheritdoc />
public string Protocol { get; }
/// <inheritdoc cref="IRequestMessage.Port" />
/// <inheritdoc />
public int Port { get; }
/// <inheritdoc cref="IRequestMessage.Origin" />
/// <inheritdoc />
public string Origin { get; }
#if USE_ASPNETCORE
/// <inheritdoc cref="IRequestMessage.ClientCertificate" />
/// <inheritdoc />
public X509Certificate2? ClientCertificate { get; }
#endif
@@ -139,11 +145,11 @@ public class RequestMessage : IRequestMessage
#if USE_ASPNETCORE
, X509Certificate2? clientCertificate = null
#endif
)
)
{
Guard.NotNull(urlDetails, nameof(urlDetails));
Guard.NotNull(method, nameof(method));
Guard.NotNull(clientIP, nameof(clientIP));
Guard.NotNull(urlDetails);
Guard.NotNull(method);
Guard.NotNull(clientIP);
AbsoluteUrl = urlDetails.AbsoluteUrl.ToString();
Url = urlDetails.Url.ToString();
@@ -166,10 +172,22 @@ public class RequestMessage : IRequestMessage
Body = BodyData?.BodyAsString;
BodyAsJson = BodyData?.BodyAsJson;
BodyAsBytes = BodyData?.BodyAsBytes;
DetectedBodyType = BodyData?.DetectedBodyType.ToString();
DetectedBodyTypeFromContentType = BodyData?.DetectedBodyTypeFromContentType.ToString();
DetectedCompression = BodyData?.DetectedCompression;
#if MIMEKIT
try
{
BodyAsMimeMessage = MimeKitUtils.GetMimeMessage(BodyData, headers![HttpKnownHeaderNames.ContentType].First());
}
catch
{
// Ignore exception from MimeMessage.Load
}
#endif
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
Cookies = cookies;
RawQuery = urlDetails.Url.Query;
@@ -180,12 +198,7 @@ public class RequestMessage : IRequestMessage
#endif
}
/// <summary>
/// Get a query parameter.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
/// <returns>The query parameter.</returns>
/// <inheritdoc />
public WireMockList<string>? GetParameter(string key, bool ignoreCase = false)
{
if (Query == null)

View File

@@ -5,7 +5,6 @@ using System.Net;
using System.Text;
using System.Threading;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Stef.Validation;
using WireMock.Admin.Mappings;
using WireMock.Constants;
@@ -19,6 +18,8 @@ using WireMock.Settings;
using WireMock.Types;
using WireMock.Util;
using static WireMock.Util.CSharpFormatter;
namespace WireMock.Serialization;
internal class MappingConverter
@@ -46,7 +47,9 @@ internal class MappingConverter
var cookieMatchers = request.GetRequestMessageMatchers<RequestMessageCookieMatcher>();
var paramsMatchers = request.GetRequestMessageMatchers<RequestMessageParamMatcher>();
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
var bodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
var requestMessageBodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
var requestMessageGraphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
var requestMessageMultiPartMatcher = request.GetRequestMessageMatcher<RequestMessageMultiPartMatcher>();
var sb = new StringBuilder();
@@ -105,13 +108,50 @@ internal class MappingConverter
sb.AppendLine($" .WithCookie(\"{cookieMatcher.Name}\", {ToValueArguments(GetStringArray(cookieMatcher.Matchers!))}, true)");
}
if (bodyMatcher is { Matchers: { } })
#if GRAPHQL
if (requestMessageGraphQLMatcher is { Matchers: { } })
{
var wildcardMatcher = bodyMatcher.Matchers.OfType<WildcardMatcher>().FirstOrDefault();
if (wildcardMatcher is { } && wildcardMatcher.GetPatterns().Any())
if (requestMessageGraphQLMatcher.Matchers.OfType<GraphQLMatcher>().FirstOrDefault() is { } graphQLMatcher && graphQLMatcher.GetPatterns().Any())
{
sb.AppendLine($" .WithGraphQLSchema({GetString(graphQLMatcher)})");
}
}
#endif
#if MIMEKIT
if (requestMessageMultiPartMatcher is { Matchers: { } })
{
if (requestMessageMultiPartMatcher.Matchers.OfType<MimePartMatcher>().Any())
{
sb.AppendLine(" // .WithMultiPart() is not yet supported");
}
}
#endif
if (requestMessageBodyMatcher is { Matchers: { } })
{
if (requestMessageBodyMatcher.Matchers.OfType<WildcardMatcher>().FirstOrDefault() is { } wildcardMatcher && wildcardMatcher.GetPatterns().Any())
{
sb.AppendLine($" .WithBody({GetString(wildcardMatcher)})");
}
else if (requestMessageBodyMatcher.Matchers.OfType<JsonPartialMatcher>().FirstOrDefault() is { Value: { } } jsonPartialMatcher)
{
sb.AppendLine(@$" .WithBody(new JsonPartialMatcher(
value: {ToCSharpStringLiteral(jsonPartialMatcher.Value.ToString())},
ignoreCase: {ToCSharpBooleanLiteral(jsonPartialMatcher.IgnoreCase)},
throwException: {ToCSharpBooleanLiteral(jsonPartialMatcher.ThrowException)},
regex: {ToCSharpBooleanLiteral(jsonPartialMatcher.Regex)}
))");
}
else if (requestMessageBodyMatcher.Matchers.OfType<JsonPartialWildcardMatcher>().FirstOrDefault() is { Value: { } } jsonPartialWildcardMatcher)
{
sb.AppendLine(@$" .WithBody(new JsonPartialWildcardMatcher(
value: {ToCSharpStringLiteral(jsonPartialWildcardMatcher.Value.ToString())},
ignoreCase: {ToCSharpBooleanLiteral(jsonPartialWildcardMatcher.IgnoreCase)},
throwException: {ToCSharpBooleanLiteral(jsonPartialWildcardMatcher.ThrowException)},
regex: {ToCSharpBooleanLiteral(jsonPartialWildcardMatcher.Regex)}
))");
}
}
sb.AppendLine(@" )");
@@ -150,18 +190,17 @@ internal class MappingConverter
{
case BodyType.String:
case BodyType.FormUrlEncoded:
sb.AppendLine($" .WithBody(\"{EscapeCSharpString(bodyData.BodyAsString)}\")");
sb.AppendLine($" .WithBody({ToCSharpStringLiteral(bodyData.BodyAsString)})");
break;
case BodyType.Json:
if (bodyData.BodyAsJson is string bodyStringValue)
{
sb.AppendLine($" .WithBody(\"{EscapeCSharpString(bodyStringValue)}\")");
sb.AppendLine($" .WithBody({ToCSharpStringLiteral(bodyStringValue)})");
}
else
else if (bodyData.BodyAsJson is { } jsonBody)
{
var serializedBody = JsonConvert.SerializeObject(bodyData.BodyAsJson);
var deserializedBody = JToken.Parse(serializedBody);
sb.AppendLine($" .WithBodyAsJson({ConvertJsonToAnonymousObjectDefinition(deserializedBody, 2)})");
var anonymousObjectDefinition = ConvertToAnonymousObjectDefinition(jsonBody);
sb.AppendLine($" .WithBodyAsJson({anonymousObjectDefinition})");
}
break;
@@ -200,6 +239,8 @@ internal class MappingConverter
var paramsMatchers = request.GetRequestMessageMatchers<RequestMessageParamMatcher>();
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
var bodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
var graphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
var multiPartMatcher = request.GetRequestMessageMatcher<RequestMessageMultiPartMatcher>();
var mappingModel = new MappingModel
{
@@ -285,7 +326,7 @@ internal class MappingConverter
mappingModel.Response.Delay = (int?)(response.Delay == Timeout.InfiniteTimeSpan ? TimeSpan.MaxValue.TotalMilliseconds : response.Delay?.TotalMilliseconds);
}
var nonNullableWebHooks = mapping.Webhooks?.Where(wh => wh != null).ToArray() ?? new IWebhook[0];
var nonNullableWebHooks = mapping.Webhooks?.Where(wh => wh != null).ToArray() ?? EmptyArray<IWebhook>.Value;
if (nonNullableWebHooks.Length == 1)
{
mappingModel.Webhook = WebhookMapper.Map(nonNullableWebHooks[0]);
@@ -295,18 +336,21 @@ internal class MappingConverter
mappingModel.Webhooks = mapping.Webhooks.Select(WebhookMapper.Map).ToArray();
}
if (bodyMatcher?.Matchers != null)
var bodyMatchers = multiPartMatcher?.Matchers ?? graphQLMatcher?.Matchers ?? bodyMatcher?.Matchers;
var matchOperator = multiPartMatcher?.MatchOperator ?? graphQLMatcher?.MatchOperator ?? bodyMatcher?.MatchOperator;
if (bodyMatchers != null && matchOperator != null)
{
mappingModel.Request.Body = new BodyModel();
if (bodyMatcher.Matchers.Length == 1)
if (bodyMatchers.Length == 1)
{
mappingModel.Request.Body.Matcher = _mapper.Map(bodyMatcher.Matchers[0]);
mappingModel.Request.Body.Matcher = _mapper.Map(bodyMatchers[0]);
}
else if (bodyMatcher.Matchers.Length > 1)
else if (bodyMatchers.Length > 1)
{
mappingModel.Request.Body.Matchers = _mapper.Map(bodyMatcher.Matchers);
mappingModel.Request.Body.MatchOperator = bodyMatcher.MatchOperator.ToString();
mappingModel.Request.Body.Matchers = _mapper.Map(bodyMatchers);
mappingModel.Request.Body.MatchOperator = matchOperator.ToString();
}
}
@@ -406,7 +450,7 @@ internal class MappingConverter
private static string GetString(IStringMatcher stringMatcher)
{
return stringMatcher.GetPatterns().Select(p => $"\"{p.GetPattern()}\"").First();
return stringMatcher.GetPatterns().Select(p => ToCSharpStringLiteral(p.GetPattern())).First();
}
private static string[] GetStringArray(IReadOnlyList<IStringMatcher> stringMatchers)
@@ -459,11 +503,9 @@ internal class MappingConverter
private static string ToValueArguments(string[]? values, string defaultValue = "")
{
return values is { } ? string.Join(", ", values.Select(v => $"\"{EscapeCSharpString(v)}\"")) : $"\"{EscapeCSharpString(defaultValue)}\"";
return values is { } ? string.Join(", ", values.Select(ToCSharpStringLiteral)) : ToCSharpStringLiteral(defaultValue);
}
private static string? EscapeCSharpString(string? value) => value?.Replace("\"", "\\\"");
private static WebProxyModel? MapWebProxy(WebProxySettings? settings)
{
return settings != null ? new WebProxyModel
@@ -492,49 +534,4 @@ internal class MappingConverter
return newDictionary;
}
private static string ConvertJsonToAnonymousObjectDefinition(JToken token, int ind = 0)
{
return token switch
{
JArray jArray => FormatArray(jArray, ind),
JObject jObject => FormatObject(jObject, ind),
JProperty jProperty => $"{jProperty.Name} = {ConvertJsonToAnonymousObjectDefinition(jProperty.Value, ind)}",
JValue jValue => jValue.Type switch
{
JTokenType.None => "null",
JTokenType.Integer => jValue.Value?.ToString() ?? "null",
JTokenType.Float => jValue.Value?.ToString() ?? "null",
JTokenType.String => $"\"{EscapeCSharpString(jValue.Value?.ToString())}\"",
JTokenType.Boolean => jValue.Value?.ToString()?.ToLower() ?? "null",
JTokenType.Null => "null",
JTokenType.Undefined => "null",
_ => $"UNHANDLED_CASE: {jValue.Type}"
},
_ => $"UNHANDLED_CASE: {token}"
};
}
private static string FormatObject(JObject jObject, int ind)
{
var indStr = new string(' ', 4 * ind);
var indStrSub = new string(' ', 4 * (ind + 1));
var items = jObject.Properties().Select(x => ConvertJsonToAnonymousObjectDefinition(x, ind + 1));
return $"new\r\n{indStr}{{\r\n{indStrSub}{string.Join($",\r\n{indStrSub}", items)}\r\n{indStr}}}";
}
private static string FormatArray(JArray jArray, int ind)
{
var hasComplexItems = jArray.FirstOrDefault() is JObject or JArray;
var items = jArray.Select(x => ConvertJsonToAnonymousObjectDefinition(x, hasComplexItems ? ind + 1 : ind));
if (hasComplexItems)
{
var indStr = new string(' ', 4 * ind);
var indStrSub = new string(' ', 4 * (ind + 1));
return $"new []\r\n{indStr}{{\r\n{indStrSub}{string.Join($",\r\n{indStrSub}", items)}\r\n{indStr}}}";
}
return $"new [] {{ {string.Join(", ", items)} }}";
}
}

View File

@@ -71,7 +71,15 @@ internal class MatcherMapper
case nameof(ExactObjectMatcher):
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0], throwExceptionWhenMatcherFails);
#if GRAPHQL
case nameof(GraphQLMatcher):
return new GraphQLMatcher(stringPatterns[0].GetPattern(), matchBehaviour, throwExceptionWhenMatcherFails, matchOperator);
#endif
#if MIMEKIT
case nameof(MimePartMatcher):
return CreateMimePartMatcher(matchBehaviour, matcher, throwExceptionWhenMatcherFails);
#endif
case nameof(RegexMatcher):
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails, useRegexExtended, matchOperator);
@@ -123,12 +131,7 @@ internal class MatcherMapper
public MatcherModel[]? Map(IEnumerable<IMatcher>? matchers)
{
if (matchers == null)
{
return null;
}
return matchers.Where(m => m != null).Select(Map).ToArray()!;
return matchers?.Where(m => m != null).Select(Map).ToArray();
}
public MatcherModel? Map(IMatcher? matcher)
@@ -192,6 +195,15 @@ internal class MatcherMapper
case ExactObjectMatcher exactObjectMatcher:
model.Pattern = exactObjectMatcher.ValueAsObject ?? exactObjectMatcher.ValueAsBytes;
break;
#if MIMEKIT
case MimePartMatcher mimePartMatcher:
model.ContentDispositionMatcher = Map(mimePartMatcher.ContentDispositionMatcher);
model.ContentMatcher = Map(mimePartMatcher.ContentMatcher);
model.ContentTransferEncodingMatcher = Map(mimePartMatcher.ContentTransferEncodingMatcher);
model.ContentTypeMatcher = Map(mimePartMatcher.ContentTypeMatcher);
break;
#endif
}
return model;
@@ -221,7 +233,7 @@ internal class MatcherMapper
return new[] { new AnyOf<string, StringPattern>(new StringPattern { Pattern = pattern, PatternAsFile = patternAsFile }) };
}
return new AnyOf<string, StringPattern>[0];
return EmptyArray<AnyOf<string, StringPattern>>.Value;
}
private static ExactObjectMatcher CreateExactObjectMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> stringPattern, bool throwException)
@@ -238,4 +250,16 @@ internal class MatcherMapper
return new ExactObjectMatcher(matchBehaviour, bytePattern, throwException);
}
#if MIMEKIT
private MimePartMatcher CreateMimePartMatcher(MatchBehaviour matchBehaviour, MatcherModel? matcher, bool throwExceptionWhenMatcherFails)
{
var contentTypeMatcher = Map(matcher?.ContentTypeMatcher) as IStringMatcher;
var contentDispositionMatcher = Map(matcher?.ContentDispositionMatcher) as IStringMatcher;
var contentTransferEncodingMatcher = Map(matcher?.ContentTransferEncodingMatcher) as IStringMatcher;
var contentMatcher = Map(matcher?.ContentMatcher);
return new MimePartMatcher(matchBehaviour, contentTypeMatcher, contentDispositionMatcher, contentTransferEncodingMatcher, contentMatcher, throwExceptionWhenMatcherFails);
}
#endif
}

View File

@@ -1,17 +1,21 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using WireMock.Extensions;
namespace WireMock.Settings;
// Based on http://blog.gauffin.org/2014/12/simple-command-line-parser/
internal class SimpleCommandLineParser
internal class SimpleSettingsParser
{
private const string Sigil = "--";
private const string Prefix = $"{nameof(WireMockServerSettings)}__";
private static readonly int PrefixLength = Prefix.Length;
private IDictionary<string, string[]> Arguments { get; } = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
public void Parse(string[] arguments)
public void Parse(string[] arguments, IDictionary? environment = null)
{
string currentName = string.Empty;
@@ -44,6 +48,18 @@ internal class SimpleCommandLineParser
{
Arguments[currentName] = values.ToArray();
}
// Now also parse environment
if (environment != null)
{
foreach (string key in environment.Keys)
{
if (key.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase) && environment.TryGetStringValue(key, out var value))
{
Arguments[key.Substring(PrefixLength)] = value.Split(' ').ToArray();
}
}
}
}
public bool Contains(string name)
@@ -85,7 +101,16 @@ internal class SimpleCommandLineParser
return Contains(name);
}
public int? GetIntValue(string name, int? defaultValue = null)
public int? GetIntValue(string name)
{
return GetValue<int?>(name, values =>
{
var value = values.FirstOrDefault();
return !string.IsNullOrEmpty(value) ? int.Parse(value) : null;
}, null);
}
public int GetIntValue(string name, int defaultValue)
{
return GetValue(name, values =>
{

View File

@@ -22,6 +22,8 @@ namespace WireMock.Settings;
/// </summary>
public class WireMockServerSettings
{
internal const int DefaultStartTimeout = 10000;
/// <summary>
/// Gets or sets the http port.
/// </summary>
@@ -81,7 +83,7 @@ public class WireMockServerSettings
/// StartTimeout
/// </summary>
[PublicAPI]
public int StartTimeout { get; set; } = 10000;
public int StartTimeout { get; set; } = DefaultStartTimeout;
/// <summary>
/// Allow Partial Mapping (default set to false).

View File

@@ -1,3 +1,4 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
@@ -18,16 +19,16 @@ public static class WireMockServerSettingsParser
/// Parse commandline arguments into WireMockServerSettings.
/// </summary>
/// <param name="args">The commandline arguments</param>
/// <param name="environment">The environment settings (optional)</param>
/// <param name="logger">The logger (optional, can be null)</param>
/// <param name="settings">The parsed settings</param>
[PublicAPI]
public static bool TryParseArguments(string[] args, [NotNullWhen(true)] out WireMockServerSettings? settings,
IWireMockLogger? logger = null)
public static bool TryParseArguments(string[] args, IDictionary? environment, [NotNullWhen(true)] out WireMockServerSettings? settings, IWireMockLogger? logger = null)
{
Guard.HasNoNulls(args);
var parser = new SimpleCommandLineParser();
parser.Parse(args);
var parser = new SimpleSettingsParser();
parser.Parse(args, environment);
if (parser.GetBoolSwitchValue("help"))
{
@@ -55,6 +56,7 @@ public static class WireMockServerSettingsParser
RequestLogExpirationDuration = parser.GetIntValue("RequestLogExpirationDuration"),
SaveUnmatchedRequests = parser.GetBoolValue(nameof(WireMockServerSettings.SaveUnmatchedRequests)),
StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true),
StartTimeout = parser.GetIntValue(nameof(WireMockServerSettings.StartTimeout), WireMockServerSettings.DefaultStartTimeout),
ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails"),
UseRegexExtended = parser.GetBoolValue(nameof(WireMockServerSettings.UseRegexExtended), true),
WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"),
@@ -79,8 +81,7 @@ public static class WireMockServerSettingsParser
return true;
}
private static void ParseLoggerSettings(WireMockServerSettings settings, IWireMockLogger? logger,
SimpleCommandLineParser parser)
private static void ParseLoggerSettings(WireMockServerSettings settings, IWireMockLogger? logger, SimpleSettingsParser parser)
{
var loggerType = parser.GetStringValue("WireMockLogger");
switch (loggerType)
@@ -103,7 +104,7 @@ public static class WireMockServerSettingsParser
}
}
private static void ParseProxyAndRecordSettings(WireMockServerSettings settings, SimpleCommandLineParser parser)
private static void ParseProxyAndRecordSettings(WireMockServerSettings settings, SimpleSettingsParser parser)
{
var proxyUrl = parser.GetStringValue("ProxyURL") ?? parser.GetStringValue("ProxyUrl");
if (!string.IsNullOrEmpty(proxyUrl))
@@ -135,7 +136,7 @@ public static class WireMockServerSettingsParser
}
}
private static void ParsePortSettings(WireMockServerSettings settings, SimpleCommandLineParser parser)
private static void ParsePortSettings(WireMockServerSettings settings, SimpleSettingsParser parser)
{
if (parser.Contains(nameof(WireMockServerSettings.Port)))
{
@@ -147,7 +148,7 @@ public static class WireMockServerSettingsParser
}
}
private static void ParseCertificateSettings(WireMockServerSettings settings, SimpleCommandLineParser parser)
private static void ParseCertificateSettings(WireMockServerSettings settings, SimpleSettingsParser parser)
{
var certificateSettings = new WireMockCertificateSettings
{
@@ -163,7 +164,7 @@ public static class WireMockServerSettingsParser
}
}
private static void ParseWebProxyAddressSettings(ProxyAndRecordSettings settings, SimpleCommandLineParser parser)
private static void ParseWebProxyAddressSettings(ProxyAndRecordSettings settings, SimpleSettingsParser parser)
{
string? proxyAddress = parser.GetStringValue("WebProxyAddress");
if (!string.IsNullOrEmpty(proxyAddress))
@@ -177,7 +178,7 @@ public static class WireMockServerSettingsParser
}
}
private static void ParseProxyUrlReplaceSettings(ProxyAndRecordSettings settings, SimpleCommandLineParser parser)
private static void ParseProxyUrlReplaceSettings(ProxyAndRecordSettings settings, SimpleSettingsParser parser)
{
var proxyUrlReplaceOldValue = parser.GetStringValue("ProxyUrlReplaceOldValue");
var proxyUrlReplaceNewValue = parser.GetStringValue("ProxyUrlReplaceNewValue");

View File

@@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace WireMock.Util;
internal static class CSharpFormatter
{
#region Reserved Keywords
private static readonly HashSet<string> CSharpReservedKeywords = new(new[]
{
"abstract",
"as",
"base",
"bool",
"break",
"byte",
"case",
"catch",
"char",
"checked",
"class",
"const",
"continue",
"decimal",
"default",
"delegate",
"do",
"double",
"else",
"enum",
"event",
"explicit",
"extern",
"false",
"finally",
"fixed",
"float",
"for",
"foreach",
"goto",
"if",
"implicit",
"in",
"int",
"interface",
"internal",
"is",
"lock",
"long",
"namespace",
"new",
"null",
"object",
"operator",
"out",
"override",
"params",
"private",
"protected",
"public",
"readonly",
"ref",
"return",
"sbyte",
"sealed",
"short",
"sizeof",
"stackalloc",
"static",
"string",
"struct",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"uint",
"ulong",
"unchecked",
"unsafe",
"ushort",
"using",
"virtual",
"void",
"volatile",
"while"
});
#endregion
private const string Null = "null";
public static object ConvertToAnonymousObjectDefinition(object jsonBody)
{
var serializedBody = JsonConvert.SerializeObject(jsonBody);
using var jsonReader = new JsonTextReader(new StringReader(serializedBody));
jsonReader.DateParseHandling = DateParseHandling.None;
var deserializedBody = JObject.Load(jsonReader);
return ConvertJsonToAnonymousObjectDefinition(deserializedBody, 2);
}
public static string ConvertJsonToAnonymousObjectDefinition(JToken token, int ind = 0)
{
return token switch
{
JArray jArray => FormatArray(jArray, ind),
JObject jObject => FormatObject(jObject, ind),
JProperty jProperty => $"{FormatPropertyName(jProperty.Name)} = {ConvertJsonToAnonymousObjectDefinition(jProperty.Value, ind)}",
JValue jValue => jValue.Type switch
{
JTokenType.None => Null,
JTokenType.Integer => jValue.Value != null ? string.Format(CultureInfo.InvariantCulture, "{0}", jValue.Value) : Null,
JTokenType.Float => jValue.Value != null ? string.Format(CultureInfo.InvariantCulture, "{0}", jValue.Value) : Null,
JTokenType.String => ToCSharpStringLiteral(jValue.Value?.ToString()),
JTokenType.Boolean => jValue.Value != null ? string.Format(CultureInfo.InvariantCulture, "{0}", jValue.Value).ToLower() : Null,
JTokenType.Null => Null,
JTokenType.Undefined => Null,
JTokenType.Date when jValue.Value is DateTime dateValue =>
$"DateTime.Parse({ToCSharpStringLiteral(dateValue.ToString("s"))})",
_ => $"UNHANDLED_CASE: {jValue.Type}"
},
_ => $"UNHANDLED_CASE: {token}"
};
}
public static string ToCSharpBooleanLiteral(bool value) => value ? "true" : "false";
public static string ToCSharpStringLiteral(string? value)
{
if (string.IsNullOrEmpty(value))
{
return "\"\"";
}
if (value.Contains('\n'))
{
var escapedValue = value?.Replace("\"", "\"\"") ?? string.Empty;
return $"@\"{escapedValue}\"";
}
else
{
var escapedValue = value?.Replace("\"", "\\\"") ?? string.Empty;
return $"\"{escapedValue}\"";
}
}
public static string FormatPropertyName(string propertyName)
{
return CSharpReservedKeywords.Contains(propertyName) ? "@" + propertyName : propertyName;
}
private static string FormatObject(JObject jObject, int ind)
{
var indStr = new string(' ', 4 * ind);
var indStrSub = new string(' ', 4 * (ind + 1));
var items = jObject.Properties().Select(x => ConvertJsonToAnonymousObjectDefinition(x, ind + 1));
return $"new\r\n{indStr}{{\r\n{indStrSub}{string.Join($",\r\n{indStrSub}", items)}\r\n{indStr}}}";
}
private static string FormatArray(JArray jArray, int ind)
{
var hasComplexItems = jArray.FirstOrDefault() is JObject or JArray;
var items = jArray.Select(x => ConvertJsonToAnonymousObjectDefinition(x, hasComplexItems ? ind + 1 : ind));
if (hasComplexItems)
{
var indStr = new string(' ', 4 * ind);
var indStrSub = new string(' ', 4 * (ind + 1));
return $"new []\r\n{indStr}{{\r\n{indStrSub}{string.Join($",\r\n{indStrSub}", items)}\r\n{indStr}}}";
}
return $"new [] {{ {string.Join(", ", items)} }}";
}
}

View File

@@ -0,0 +1,42 @@
#if MIMEKIT
using System;
using System.IO;
using System.Text;
using MimeKit;
using WireMock.Http;
using WireMock.Types;
namespace WireMock.Util;
internal static class MimeKitUtils
{
public static MimeMessage GetMimeMessage(IBodyData? bodyData, string contentTypeHeaderValue)
{
var bytes = bodyData?.DetectedBodyType switch
{
// If the body is bytes, use the BodyAsBytes to match on.
BodyType.Bytes => bodyData.BodyAsBytes!,
// If the body is a String or MultiPart, use the BodyAsString to match on.
BodyType.String or BodyType.MultiPart => Encoding.UTF8.GetBytes(bodyData.BodyAsString!),
_ => throw new NotSupportedException()
};
var fixedBytes = FixBytes(bytes, contentTypeHeaderValue);
return MimeMessage.Load(new MemoryStream(fixedBytes));
}
private static byte[] FixBytes(byte[] bytes, WireMockList<string> contentType)
{
var contentTypeBytes = Encoding.UTF8.GetBytes($"{HttpKnownHeaderNames.ContentType}: {contentType}\r\n\r\n");
var result = new byte[contentTypeBytes.Length + bytes.Length];
Buffer.BlockCopy(contentTypeBytes, 0, result, 0, contentTypeBytes.Length);
Buffer.BlockCopy(bytes, 0, result, contentTypeBytes.Length, bytes.Length);
return result;
}
}
#endif

View File

@@ -0,0 +1,12 @@
using System.IO;
using System.Text;
namespace WireMock.Util;
internal static class StreamUtils
{
public static Stream CreateStream(string s)
{
return new MemoryStream(Encoding.UTF8.GetBytes(s));
}
}

View File

@@ -50,16 +50,20 @@
<DefineConstants>$(DefineConstants);OPENAPIPARSER</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Matchers\MultiPartMatcher.cs" />
<Compile Remove="Util\FileSystemWatcherExtensions.cs" />
<Compile Remove="Matchers\Request\IRequestMatcher.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
<PackageReference Include="JsonConverter.Abstractions" Version="0.4.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NJsonSchema.Extensions" Version="0.1.0" />
<PackageReference Include="NSwag.Core" Version="13.16.1" />
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
@@ -154,6 +158,12 @@
<PackageReference Include="Scriban.Signed" Version="5.5.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
<PackageReference Include="GraphQL" Version="7.5.0" />
<PackageReference Include="GraphQL.NewtonsoftJson" Version="7.5.0" />
<PackageReference Include="MimeKitLite" Version="4.1.0.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<PackageReference Include="Nullable" Version="1.3.1">
<PrivateAssets>all</PrivateAssets>
@@ -180,13 +190,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Handlebars.Net.Helpers" Version="2.3.15" />
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.3.15" />
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.3.15" />
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.3.15" />
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.3.15" />
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.3.15" />
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.3.15" />
<PackageReference Include="Handlebars.Net.Helpers" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.4.0" />
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.4.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,51 @@
using System.Collections;
using FluentAssertions;
using WireMock.Extensions;
using Xunit;
namespace WireMock.Net.Tests.Extensions;
public class DictionaryExtensionsTests
{
[Fact]
public void TryGetStringValue_WhenKeyExistsAndValueIsString_ReturnsTrueAndStringValue()
{
// Arrange
var dictionary = new Hashtable { { "key", "value" } };
// Act
var result = dictionary.TryGetStringValue("key", out var value);
// Assert
result.Should().BeTrue();
value.Should().Be("value");
}
[Fact]
public void TryGetStringValue_WhenKeyExistsAndValueIsNotString_ReturnsTrueAndStringValue()
{
// Arrange
var dictionary = new Hashtable { { "key", 123 } };
// Act
var result = dictionary.TryGetStringValue("key", out var value);
// Assert
result.Should().BeTrue();
value.Should().Be("123");
}
[Fact]
public void TryGetStringValue_WhenKeyDoesNotExist_ReturnsFalseAndNull()
{
// Arrange
var dictionary = new Hashtable { { "otherKey", "value" } };
// Act
var result = dictionary.TryGetStringValue("key", out var value);
// Assert
result.Should().BeFalse();
value.Should().BeNull();
}
}

View File

@@ -210,6 +210,36 @@ public class WireMockAssertionsTests : IDisposable
.Be($"{string.Join(NewLine, missingValue1Message, missingValue2Message)}{NewLine}");
}
[Fact]
public async Task HaveReceivedACall_WithHeader_ShouldCheckAllRequests()
{
// Arrange
using var server = WireMockServer.Start();
using var client = server.CreateClient();
// Act 1
await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
{
Headers =
{
Authorization = new AuthenticationHeaderValue("Bearer", "invalidToken")
}
});
// Act 2
await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
{
Headers =
{
Authorization = new AuthenticationHeaderValue("Bearer", "validToken")
}
});
// Assert
server.Should().HaveReceivedACall().WithHeader("Authorization", "Bearer invalidToken");
server.Should().HaveReceivedACall().WithHeader("Authorization", "Bearer validToken");
}
[Fact]
public async Task HaveReceivedACall_AtUrl_WhenACallWasMadeToUrl_Should_BeOK()
{

View File

@@ -1,7 +1,9 @@
using NFluent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using WireMock.Http;
using WireMock.Models;
using WireMock.Types;
@@ -160,4 +162,29 @@ public class HttpRequestMessageHelperTests
// Assert
Check.That(message.Content.Headers.GetValues("Content-Type")).ContainsExactly("application/xml; charset=Ascii");
}
[Theory]
[InlineData("HEAD", true)]
[InlineData("GET", false)]
[InlineData("PUT", false)]
[InlineData("POST", false)]
[InlineData("DELETE", false)]
[InlineData("TRACE", false)]
[InlineData("OPTIONS", false)]
[InlineData("CONNECT", false)]
[InlineData("PATCH", false)]
public void HttpRequestMessageHelper_Create_ContentLengthAllowedForMethod(string method, bool resultShouldBe)
{
// Arrange
var key = "Content-Length";
var value = 1234;
var headers = new Dictionary<string, string[]> { { key, new[] { "1234" } } };
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), method, ClientIp, null, headers);
// Act
var message = HttpRequestMessageHelper.Create(request, "http://url");
// Assert
message.Content?.Headers.ContentLength.Should().Be(resultShouldBe ? value : null);
}
}

View File

@@ -14,6 +14,17 @@
},
Methods: [
GET
],
Params: [
{
Name: test,
Matchers: [
{
Name: LinqMatcher,
Pattern: it.Length < 10
}
]
}
]
},
Response: {

View File

@@ -14,6 +14,17 @@
},
Methods: [
GET
],
Params: [
{
Name: test,
Matchers: [
{
Name: LinqMatcher,
Pattern: it.Length < 10
}
]
}
]
},
Response: {

View File

@@ -6,6 +6,7 @@ using VerifyTests;
using VerifyXunit;
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.Net.Tests.VerifyExtensions;
using WireMock.Owin;
using WireMock.RequestBuilders;
@@ -65,6 +66,7 @@ public class MappingBuilderTests
_sut.Given(Request.Create()
.WithPath("/foo")
.WithParam("test", new LinqMatcher("it.Length < 10"))
.UsingGet()
)
.WithGuid(MappingGuid)

View File

@@ -0,0 +1,142 @@
#if GRAPHQL
using System;
using FluentAssertions;
using GraphQLParser.Exceptions;
using WireMock.Matchers;
using WireMock.Models;
using Xunit;
namespace WireMock.Net.Tests.Matchers;
public class GraphQLMatcherTests
{
private const string TestSchema = @"
input MessageInput {
content: String
author: String
}
type Message {
id: ID!
content: String
author: String
}
type Mutation {
createMessage(input: MessageInput): Message
updateMessage(id: ID!, input: MessageInput): Message
}
type Query {
greeting:String
students:[Student]
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
}";
[Fact]
public void GraphQLMatcher_For_ValidSchema_And_CorrectQuery_IsMatch()
{
// Arrange
var input = "{\"query\":\"{\\r\\n students {\\r\\n fullName\\r\\n id\\r\\n }\\r\\n}\"}";
// Act
var matcher = new GraphQLMatcher(TestSchema);
var result = matcher.IsMatch(input);
// Assert
result.Should().Be(MatchScores.Perfect);
matcher.GetPatterns().Should().Contain(TestSchema);
}
[Fact]
public void GraphQLMatcher_For_ValidSchema_And_CorrectGraphQLQuery_IsMatch()
{
// Arrange
var input = @"{
""query"": ""query ($sid: ID!)\r\n{\r\n studentById(id: $sid) {\r\n fullName\r\n id\r\n }\r\n}"",
""variables"": {
""sid"": ""1""
}
}";
// Act
var matcher = new GraphQLMatcher(TestSchema);
var result = matcher.IsMatch(input);
// Assert
result.Should().Be(MatchScores.Perfect);
matcher.GetPatterns().Should().Contain(TestSchema);
}
[Fact]
public void GraphQLMatcher_For_ValidSchema_And_IncorrectQuery_IsMismatch()
{
// Arrange
var input = @"
{
students {
fullName
id
abc
}
}";
// Act
var matcher = new GraphQLMatcher(TestSchema);
var result = matcher.IsMatch(input);
// Assert
result.Should().Be(MatchScores.Mismatch);
}
[Fact]
public void GraphQLMatcher_For_ValidSchemaAsStringPattern_And_CorrectQuery_IsMatch()
{
// Arrange
var input = "{\"query\":\"{\\r\\n students {\\r\\n fullName\\r\\n id\\r\\n }\\r\\n}\"}";
var schema = new StringPattern
{
Pattern = TestSchema
};
// Act
var matcher = new GraphQLMatcher(schema);
var result = matcher.IsMatch(input);
// Assert
result.Should().Be(MatchScores.Perfect);
}
[Fact]
public void GraphQLMatcher_For_ValidSchema_And_IncorrectQueryWithError_WithThrowExceptionTrue_ThrowsException()
{
// Arrange
var input = "{\"query\":\"{\\r\\n studentsX {\\r\\n fullName\\r\\n X\\r\\n }\\r\\n}\"}";
// Act
var matcher = new GraphQLMatcher(TestSchema, MatchBehaviour.AcceptOnMatch, true);
Action action = () => matcher.IsMatch(input);
// Assert
action.Should().Throw<Exception>();
}
[Fact]
public void GraphQLMatcher_For_InvalidSchema_ThrowsGraphQLSyntaxErrorException()
{
// Act
// ReSharper disable once ObjectCreationAsStatement
Action action = () => _ = new GraphQLMatcher("in va lid");
// Assert
action.Should().Throw<GraphQLSyntaxErrorException>();
}
}
#endif

View File

@@ -199,6 +199,27 @@ public class JsonPartialMatcherTests
Assert.Equal(0.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_GuidAsString_UsingRegex()
{
var guid = new Guid("1111238e-b775-44a9-a263-95e570135c94");
var matcher = new JsonPartialMatcher(new {
Id = 1,
Name = "^1111[a-fA-F0-9]{4}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"
}, false, false, true);
// Act
var jObject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue(guid) }
};
double match = matcher.IsMatch(jObject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_WithIgnoreCaseTrue_JObject()
{
@@ -281,6 +302,25 @@ public class JsonPartialMatcherTests
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_GuidAsString()
{
// Assign
var guid = Guid.NewGuid();
var matcher = new JsonPartialMatcher(new { Id = 1, Name = guid });
// Act
var jObject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue(guid.ToString()) }
};
double match = matcher.IsMatch(jObject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonPartialMatcher_IsMatch_WithIgnoreCaseTrue_JObjectAsString()
{

View File

@@ -11,7 +11,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_GetName()
{
// Assign
// Arrange
var matcher = new JsonPathMatcher("X");
// Act
@@ -24,7 +24,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_GetPatterns()
{
// Assign
// Arrange
var matcher = new JsonPathMatcher("X");
// Act
@@ -37,7 +37,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_IsMatch_ByteArray()
{
// Assign
// Arrange
var bytes = EmptyArray<byte>.Value;
var matcher = new JsonPathMatcher("");
@@ -51,7 +51,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_IsMatch_NullString()
{
// Assign
// Arrange
string? s = null;
var matcher = new JsonPathMatcher("");
@@ -65,7 +65,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_IsMatch_NullObject()
{
// Assign
// Arrange
object? o = null;
var matcher = new JsonPathMatcher("");
@@ -79,7 +79,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_IsMatch_String_Exception_Mismatch()
{
// Assign
// Arrange
var matcher = new JsonPathMatcher("xxx");
// Act
@@ -92,7 +92,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_IsMatch_Object_Exception_Mismatch()
{
// Assign
// Arrange
var matcher = new JsonPathMatcher("");
// Act
@@ -105,7 +105,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_IsMatch_AnonymousObject()
{
// Assign
// Arrange
var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]");
// Act
@@ -115,10 +115,51 @@ public class JsonPathMatcherTests
Check.That(match).IsEqualTo(1);
}
[Fact]
public void JsonPathMatcher_IsMatch_AnonymousObject_WithNestedObject()
{
// Arrange
var matcher = new JsonPathMatcher("$.things[?(@.name == 'x')]");
// Act
double match = matcher.IsMatch(new { things = new { name = "x" } });
// Assert
Check.That(match).IsEqualTo(1);
}
[Fact]
public void JsonPathMatcher_IsMatch_String_WithNestedObject()
{
// Arrange
var json = "{ \"things\": { \"name\": \"x\" } }";
var matcher = new JsonPathMatcher("$.things[?(@.name == 'x')]");
// Act
double match = matcher.IsMatch(json);
// Assert
Check.That(match).IsEqualTo(1);
}
[Fact]
public void JsonPathMatcher_IsNoMatch_String_WithNestedObject()
{
// Arrange
var json = "{ \"things\": { \"name\": \"y\" } }";
var matcher = new JsonPathMatcher("$.things[?(@.name == 'x')]");
// Act
double match = matcher.IsMatch(json);
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonPathMatcher_IsMatch_JObject()
{
// Assign
// Arrange
string[] patterns = { "$..[?(@.Id == 1)]" };
var matcher = new JsonPathMatcher(patterns);
@@ -137,7 +178,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_IsMatch_JObject_Parsed()
{
// Assign
// Arrange
var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]");
// Act
@@ -150,7 +191,7 @@ public class JsonPathMatcherTests
[Fact]
public void JsonPathMatcher_IsMatch_RejectOnMatch()
{
// Assign
// Arrange
var matcher = new JsonPathMatcher(MatchBehaviour.RejectOnMatch, false, MatchOperator.Or, "$..[?(@.Id == 1)]");
// Act
@@ -159,4 +200,128 @@ public class JsonPathMatcherTests
// Assert
Check.That(match).IsEqualTo(0.0);
}
}
[Fact]
public void JsonPathMatcher_IsMatch_ArrayOneLevel()
{
// Arrange
var matcher = new JsonPathMatcher("$.arr[0].line1");
// Act
double match = matcher.IsMatch(JObject.Parse(@"{
""name"": ""PathSelectorTest"",
""test"": ""test"",
""test2"": ""test2"",
""arr"": [{
""line1"": ""line1"",
}]
}"));
// Assert
Check.That(match).IsEqualTo(1.0);
}
[Fact]
public void JsonPathMatcher_IsMatch_ObjectMatch()
{
// Arrange
var matcher = new JsonPathMatcher("$.test");
// Act
double match = matcher.IsMatch(JObject.Parse(@"{
""name"": ""PathSelectorTest"",
""test"": ""test"",
""test2"": ""test2"",
""arr"": [
{
""line1"": ""line1"",
}
]
}"));
// Assert
Check.That(match).IsEqualTo(1.0);
}
[Fact]
public void JsonPathMatcher_IsMatch_DoesntMatch()
{
// Arrange
var matcher = new JsonPathMatcher("$.test3");
// Act
double match = matcher.IsMatch(JObject.Parse(@"{
""name"": ""PathSelectorTest"",
""test"": ""test"",
""test2"": ""test2"",
""arr"": [
{
""line1"": ""line1"",
}
]
}"));
// Assert
Check.That(match).IsEqualTo(0.0);
}
[Fact]
public void JsonPathMatcher_IsMatch_DoesntMatchInArray()
{
// Arrange
var matcher = new JsonPathMatcher("$arr[0].line1");
// Act
double match = matcher.IsMatch(JObject.Parse(@"{
""name"": ""PathSelectorTest"",
""test"": ""test"",
""test2"": ""test2"",
""arr"": []
}"));
// Assert
Check.That(match).IsEqualTo(0.0);
}
[Fact]
public void JsonPathMatcher_IsMatch_DoesntMatchNoObjectsInArray()
{
// Arrange
var matcher = new JsonPathMatcher("$arr[2].line1");
// Act
double match = matcher.IsMatch(JObject.Parse(@"{
""name"": ""PathSelectorTest"",
""test"": ""test"",
""test2"": ""test2"",
""arr"": []
}"));
// Assert
Check.That(match).IsEqualTo(0.0);
}
[Fact]
public void JsonPathMatcher_IsMatch_NestedArrays()
{
// Arrange
var matcher = new JsonPathMatcher("$.arr[0].sub[0].subline1");
// Act
double match = matcher.IsMatch(JObject.Parse(@"{
""name"": ""PathSelectorTest"",
""test"": ""test"",
""test2"": ""test2"",
""arr"": [{
""line1"": ""line1"",
""sub"":[
{
""subline1"":""subline1""
}]
}]
}"));
// Assert
Check.That(match).IsEqualTo(1.0);
}
}

View File

@@ -0,0 +1,99 @@
#if MIMEKIT
using System;
using System.Linq;
using FluentAssertions;
using MimeKit;
using WireMock.Matchers;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests.Matchers;
public class MimePartMatcherTests
{
private const string TestMultiPart = @"From:
Date: Sun, 23 Jul 2023 16:13:13 +0200
Subject:
Message-Id: <HZ3K1HEAJKU4.IO57XCVO4BWV@desktop-6dd5qi2>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=""=-5XgmpXt0XOfzdtcgNJc2ZQ==""
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
Content-Type: text/plain; charset=utf-8
This is some plain text
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
Content-Type: text/json; charset=utf-8
{
""Key"": ""Value""
}
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
Content-Type: image/png; name=image.png
Content-Disposition: attachment; filename=image.png
Content-Transfer-Encoding: base64
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjl
AAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC
--=-5XgmpXt0XOfzdtcgNJc2ZQ==--
";
[Fact]
public void MimePartMatcher_IsMatch_Part_TextPlain()
{
// Arrange
var message = MimeMessage.Load(StreamUtils.CreateStream(TestMultiPart));
var part = (MimePart)message.BodyParts.ToArray()[0];
// Act
var contentTypeMatcher = new ContentTypeMatcher("text/plain");
var contentMatcher = new ExactMatcher("This is some plain text");
var matcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, contentTypeMatcher, null, null, contentMatcher);
var result = matcher.IsMatch(part);
// Assert
matcher.Name.Should().Be("MimePartMatcher");
result.Should().Be(MatchScores.Perfect);
}
[Fact]
public void MimePartMatcher_IsMatch_Part_TextJson()
{
// Arrange
var message = MimeMessage.Load(StreamUtils.CreateStream(TestMultiPart));
var part = (MimePart)message.BodyParts.ToArray()[1];
// Act
var contentTypeMatcher = new ContentTypeMatcher("text/json");
var contentMatcher = new JsonMatcher(new { Key = "Value" }, true);
var matcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, contentTypeMatcher, null, null, contentMatcher);
var result = matcher.IsMatch(part);
// Assert
result.Should().Be(MatchScores.Perfect);
}
[Fact]
public void MimePartMatcher_IsMatch_Part_ImagePng()
{
// Arrange
var message = MimeMessage.Load(StreamUtils.CreateStream(TestMultiPart));
var part = (MimePart)message.BodyParts.ToArray()[2];
// Act
var contentTypeMatcher = new ContentTypeMatcher("image/png");
var contentDispositionMatcher = new ExactMatcher("attachment; filename=\"image.png\"");
var contentTransferEncodingMatcher = new ExactMatcher("base64");
var contentMatcher = new ExactObjectMatcher(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC"));
var matcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, contentTypeMatcher, contentDispositionMatcher, contentTransferEncodingMatcher, contentMatcher);
var result = matcher.IsMatch(part);
// Assert
result.Should().Be(MatchScores.Perfect);
}
}
#endif

View File

@@ -42,7 +42,14 @@ public class PactTests
})
);
server.SavePact(Path.Combine("../../../", "Pact", "files"), "pact-get.json");
var folder = Path.Combine("../../../", "Pact", "files");
var file = "pact-get.json";
// Act
server.SavePact(folder, file);
// Assert
File.ReadAllBytes(Path.Combine(folder, file)).Length.Should().BeGreaterThan(1);
}
[Fact]
@@ -201,6 +208,13 @@ public class PactTests
})
);
server.SavePact(Path.Combine("../../../", "Pact", "files"), "pact-multiple.json");
var folder = Path.Combine("../../../", "Pact", "files");
var file = "pact-multiple.json";
// Act
server.SavePact(folder, file);
// Assert
File.ReadAllBytes(Path.Combine(folder, file)).Length.Should().BeGreaterThan(1);
}
}

Some files were not shown because too many files have changed in this diff Show More