diff --git a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs
index 0ad7dfa6..9ea422e8 100644
--- a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs
+++ b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs
@@ -79,7 +79,7 @@ namespace WireMock.Net.ConsoleApplication
// server.AllowPartialMapping();
- server.Given(Request.Create().WithPath("/mypath").UsingPost())
+ server.Given(Request.Create().WithPath(MatchOperator.Or, "/mypath", "/mypath1", "/mypath2").UsingPost())
.RespondWith(Response.Create()
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson("{{JsonPath.SelectToken request.body \"..name\"}}")
diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/BodyModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/BodyModel.cs
index 52d2f7f0..86dd4381 100644
--- a/src/WireMock.Net.Abstractions/Admin/Mappings/BodyModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Mappings/BodyModel.cs
@@ -1,19 +1,27 @@
-namespace WireMock.Admin.Mappings
+namespace WireMock.Admin.Mappings;
+
+///
+/// Body Model
+///
+[FluentBuilder.AutoGenerateBuilder]
+public class BodyModel
{
///
- /// Body Model
+ /// Gets or sets the matcher.
///
- [FluentBuilder.AutoGenerateBuilder]
- public class BodyModel
- {
- ///
- /// Gets or sets the matcher.
- ///
- public MatcherModel? Matcher { get; set; }
+ public MatcherModel? Matcher { get; set; }
- ///
- /// Gets or sets the matchers.
- ///
- public MatcherModel[]? Matchers { get; set; }
- }
+ ///
+ /// Gets or sets the matchers.
+ ///
+ public MatcherModel[]? Matchers { get; set; }
+
+ ///
+ /// The Operator to use when matchers are defined. [Optional]
+ /// - null = Same as "or".
+ /// - "or" = Only one pattern should match.
+ /// - "and" = All patterns should match.
+ /// - "average" = The average value from all patterns.
+ ///
+ public string? MatchOperator { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/ClientIPModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/ClientIPModel.cs
index af1dc24f..bba78a94 100644
--- a/src/WireMock.Net.Abstractions/Admin/Mappings/ClientIPModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Mappings/ClientIPModel.cs
@@ -1,14 +1,22 @@
-namespace WireMock.Admin.Mappings
+namespace WireMock.Admin.Mappings;
+
+///
+/// ClientIPModel
+///
+[FluentBuilder.AutoGenerateBuilder]
+public class ClientIPModel
{
///
- /// ClientIPModel
+ /// Gets or sets the matchers.
///
- [FluentBuilder.AutoGenerateBuilder]
- public class ClientIPModel
- {
- ///
- /// Gets or sets the matchers.
- ///
- public MatcherModel[] Matchers { get; set; }
- }
+ public MatcherModel[]? Matchers { get; set; }
+
+ ///
+ /// The Operator to use when matchers are defined. [Optional]
+ /// - null = Same as "or".
+ /// - "or" = Only one pattern should match.
+ /// - "and" = All patterns should match.
+ /// - "average" = The average value from all patterns.
+ ///
+ public string? MatchOperator { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/HeaderModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/HeaderModel.cs
index 724c11b9..ea8882c4 100644
--- a/src/WireMock.Net.Abstractions/Admin/Mappings/HeaderModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Mappings/HeaderModel.cs
@@ -1,31 +1,39 @@
using System.Collections.Generic;
-namespace WireMock.Admin.Mappings
+namespace WireMock.Admin.Mappings;
+
+///
+/// Header Model
+///
+[FluentBuilder.AutoGenerateBuilder]
+public class HeaderModel
{
///
- /// Header Model
+ /// Gets or sets the name.
///
- [FluentBuilder.AutoGenerateBuilder]
- public class HeaderModel
- {
- ///
- /// Gets or sets the name.
- ///
- public string Name { get; set; } = null!;
+ public string Name { get; set; } = null!;
- ///
- /// Gets or sets the matchers.
- ///
- public IList? Matchers { get; set; }
+ ///
+ /// Gets or sets the matchers.
+ ///
+ public IList? Matchers { get; set; }
- ///
- /// Gets or sets the ignore case.
- ///
- public bool? IgnoreCase { get; set; }
+ ///
+ /// Gets or sets the ignore case.
+ ///
+ public bool? IgnoreCase { get; set; }
- ///
- /// Reject on match.
- ///
- public bool? RejectOnMatch { get; set; }
- }
+ ///
+ /// Reject on match.
+ ///
+ public bool? RejectOnMatch { get; set; }
+
+ ///
+ /// The Operator to use when matchers are defined. [Optional]
+ /// - null = Same as "or".
+ /// - "or" = Only one pattern should match.
+ /// - "and" = All patterns should match.
+ /// - "average" = The average value from all patterns.
+ ///
+ public string? MatchOperator { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs
index e9544e8e..693143a7 100644
--- a/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Mappings/MappingModel.cs
@@ -1,78 +1,77 @@
using System;
using WireMock.Models;
-namespace WireMock.Admin.Mappings
+namespace WireMock.Admin.Mappings;
+
+///
+/// MappingModel
+///
+[FluentBuilder.AutoGenerateBuilder]
+public class MappingModel
{
///
- /// MappingModel
+ /// Gets or sets the unique identifier.
///
- [FluentBuilder.AutoGenerateBuilder]
- public class MappingModel
- {
- ///
- /// Gets or sets the unique identifier.
- ///
- public Guid? Guid { get; set; }
+ public Guid? Guid { get; set; }
- ///
- /// Gets or sets the TimeSettings when which this mapping should be used.
- ///
- public TimeSettingsModel TimeSettings { get; set; }
+ ///
+ /// Gets or sets the TimeSettings when which this mapping should be used.
+ ///
+ public TimeSettingsModel? TimeSettings { get; set; }
- ///
- /// The unique title.
- ///
- public string Title { get; set; }
+ ///
+ /// The unique title.
+ ///
+ public string? Title { get; set; }
- ///
- /// The description.
- ///
- public string Description { get; set; }
+ ///
+ /// The description.
+ ///
+ public string? Description { get; set; }
- ///
- /// The priority. (A low value means higher priority.)
- ///
- public int? Priority { get; set; }
+ ///
+ /// The priority. (A low value means higher priority.)
+ ///
+ public int? Priority { get; set; }
- ///
- /// The Scenario.
- ///
- public string Scenario { get; set; }
+ ///
+ /// The Scenario.
+ ///
+ public string? Scenario { get; set; }
- ///
- /// Execution state condition for the current mapping.
- ///
- public string WhenStateIs { get; set; }
+ ///
+ /// Execution state condition for the current mapping.
+ ///
+ public string? WhenStateIs { get; set; }
- ///
- /// The next state which will be signaled after the current mapping execution.
- /// In case the value is null state will not be changed.
- ///
- public string SetStateTo { get; set; }
+ ///
+ /// The next state which will be signaled after the current mapping execution.
+ /// In case the value is null state will not be changed.
+ ///
+ public string? SetStateTo { get; set; }
- ///
- /// The request model.
- ///
- public RequestModel Request { get; set; }
+ ///
+ /// The request model.
+ ///
+ public RequestModel Request { get; set; }
- ///
- /// The response model.
- ///
- public ResponseModel Response { get; set; }
+ ///
+ /// The response model.
+ ///
+ public ResponseModel Response { get; set; }
- ///
- /// Saves this mapping as a static mapping file.
- ///
- public bool? SaveToFile { get; set; }
+ ///
+ /// Saves this mapping as a static mapping file.
+ ///
+ public bool? SaveToFile { get; set; }
- ///
- /// The Webhook.
- ///
- public WebhookModel Webhook { get; set; }
+ ///
+ /// The Webhook.
+ ///
+ public WebhookModel? Webhook { get; set; }
- ///
- /// The Webhooks.
- ///
- public WebhookModel[] Webhooks { get; set; }
- }
+ ///
+ /// The Webhooks.
+ ///
+ public WebhookModel[]? Webhooks { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/MatcherModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/MatcherModel.cs
index 1c1cda31..51e08357 100644
--- a/src/WireMock.Net.Abstractions/Admin/Mappings/MatcherModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Mappings/MatcherModel.cs
@@ -35,5 +35,14 @@ namespace WireMock.Admin.Mappings
/// Reject on match.
///
public bool? RejectOnMatch { get; set; }
+
+ ///
+ /// The Operator to use when multiple patterns are defined. Optional.
+ /// - null = Same as "or".
+ /// - "or" = Only one pattern should match.
+ /// - "and" = All patterns should match.
+ /// - "average" = The average value from all patterns.
+ ///
+ public string? MatchOperator { get; set; }
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/PathModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/PathModel.cs
index 8122c898..9413d3fe 100644
--- a/src/WireMock.Net.Abstractions/Admin/Mappings/PathModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Mappings/PathModel.cs
@@ -1,14 +1,22 @@
-namespace WireMock.Admin.Mappings
+namespace WireMock.Admin.Mappings;
+
+///
+/// PathModel
+///
+[FluentBuilder.AutoGenerateBuilder]
+public class PathModel
{
///
- /// PathModel
+ /// Gets or sets the matchers.
///
- [FluentBuilder.AutoGenerateBuilder]
- public class PathModel
- {
- ///
- /// Gets or sets the matchers.
- ///
- public MatcherModel[]? Matchers { get; set; }
- }
+ public MatcherModel[]? Matchers { get; set; }
+
+ ///
+ /// The Operator to use when matchers are defined. [Optional]
+ /// - null = Same as "or".
+ /// - "or" = Only one pattern should match.
+ /// - "and" = All patterns should match.
+ /// - "average" = The average value from all patterns.
+ ///
+ public string? MatchOperator { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/RequestModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/RequestModel.cs
index 3f396685..b3b25cd8 100644
--- a/src/WireMock.Net.Abstractions/Admin/Mappings/RequestModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Mappings/RequestModel.cs
@@ -28,6 +28,20 @@ public class RequestModel
///
public string[]? Methods { get; set; }
+ ///
+ /// Reject on match for Methods.
+ ///
+ public bool? MethodsRejectOnMatch { get; set; }
+
+ ///
+ /// The Operator to use when Methods are defined. [Optional]
+ /// - null = Same as "or".
+ /// - "or" = Only one method should match.
+ /// - "and" = All methods should match.
+ /// - "average" = The average value from all methods.
+ ///
+ public string? MethodsMatchOperator { get; set; }
+
///
/// Gets or sets the Headers.
///
diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/UrlModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/UrlModel.cs
index eb6df454..57348abf 100644
--- a/src/WireMock.Net.Abstractions/Admin/Mappings/UrlModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Mappings/UrlModel.cs
@@ -1,14 +1,22 @@
-namespace WireMock.Admin.Mappings
+namespace WireMock.Admin.Mappings;
+
+///
+/// UrlModel
+///
+[FluentBuilder.AutoGenerateBuilder]
+public class UrlModel
{
///
- /// UrlModel
+ /// Gets or sets the matchers.
///
- [FluentBuilder.AutoGenerateBuilder]
- public class UrlModel
- {
- ///
- /// Gets or sets the matchers.
- ///
- public MatcherModel[] Matchers { get; set; }
- }
-}
+ public MatcherModel[]? Matchers { get; set; }
+
+ ///
+ /// The Operator to use when matchers are defined. [Optional]
+ /// - null = Same as "or".
+ /// - "or" = Only one pattern should match.
+ /// - "and" = All patterns should match.
+ /// - "average" = The average value from all patterns.
+ ///
+ public string? MatchOperator { get; set; }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/IRequestMessage.cs b/src/WireMock.Net.Abstractions/IRequestMessage.cs
index 39cd3f86..ca80ec89 100644
--- a/src/WireMock.Net.Abstractions/IRequestMessage.cs
+++ b/src/WireMock.Net.Abstractions/IRequestMessage.cs
@@ -3,136 +3,135 @@ using System.Collections.Generic;
using WireMock.Types;
using WireMock.Util;
-namespace WireMock
+namespace WireMock;
+
+///
+/// IRequestMessage
+///
+public interface IRequestMessage
{
///
- /// IRequestMessage
+ /// Gets the Client IP Address.
///
- public interface IRequestMessage
- {
- ///
- /// Gets the Client IP Address.
- ///
- string ClientIP { get; }
+ string ClientIP { get; }
- ///
- /// Gets the url (relative).
- ///
- string Url { get; }
+ ///
+ /// Gets the url (relative).
+ ///
+ string Url { get; }
- ///
- /// Gets the AbsoluteUrl.
- ///
- string AbsoluteUrl { get; }
+ ///
+ /// Gets the AbsoluteUrl.
+ ///
+ string AbsoluteUrl { get; }
- ///
- /// The ProxyUrl (if a proxy is used).
- ///
- string ProxyUrl { get; set; }
+ ///
+ /// The ProxyUrl (if a proxy is used).
+ ///
+ string ProxyUrl { get; set; }
- ///
- /// Gets the DateTime.
- ///
- DateTime DateTime { get; }
+ ///
+ /// Gets the DateTime.
+ ///
+ DateTime DateTime { get; }
- ///
- /// Gets the path (relative).
- ///
- string Path { get; }
+ ///
+ /// Gets the path (relative).
+ ///
+ string Path { get; }
- ///
- /// Gets the AbsolutePath.
- ///
- string AbsolutePath { get; }
+ ///
+ /// Gets the AbsolutePath.
+ ///
+ string AbsolutePath { get; }
- ///
- /// Gets the path segments.
- ///
- string[] PathSegments { get; }
+ ///
+ /// Gets the path segments.
+ ///
+ string[] PathSegments { get; }
- ///
- /// Gets the absolute path segments.
- ///
- string[] AbsolutePathSegments { get; }
+ ///
+ /// Gets the absolute path segments.
+ ///
+ string[] AbsolutePathSegments { get; }
- ///
- /// Gets the method.
- ///
- string Method { get; }
+ ///
+ /// Gets the method.
+ ///
+ string Method { get; }
- ///
- /// Gets the headers.
- ///
- IDictionary> Headers { get; }
+ ///
+ /// Gets the headers.
+ ///
+ IDictionary>? Headers { get; }
- ///
- /// Gets the cookies.
- ///
- IDictionary Cookies { get; }
+ ///
+ /// Gets the cookies.
+ ///
+ IDictionary? Cookies { get; }
- ///
- /// Gets the query.
- ///
- IDictionary> Query { get; }
+ ///
+ /// Gets the query.
+ ///
+ IDictionary>? Query { get; }
- ///
- /// Gets the raw query.
- ///
- string RawQuery { get; }
+ ///
+ /// Gets the raw query.
+ ///
+ string RawQuery { get; }
- ///
- /// The body.
- ///
- IBodyData? BodyData { get; }
+ ///
+ /// The body.
+ ///
+ IBodyData? BodyData { get; }
- ///
- /// The original body as string. Convenience getter for Handlebars.
- ///
- string Body { get; }
+ ///
+ /// The original body as string. Convenience getter for Handlebars.
+ ///
+ string Body { get; }
- ///
- /// The body (as JSON object). Convenience getter for Handlebars.
- ///
- object BodyAsJson { get; }
+ ///
+ /// The body (as JSON object). Convenience getter for Handlebars.
+ ///
+ object BodyAsJson { get; }
- ///
- /// The body (as bytearray). Convenience getter for Handlebars.
- ///
- byte[] BodyAsBytes { get; }
+ ///
+ /// The body (as bytearray). Convenience getter for Handlebars.
+ ///
+ byte[] BodyAsBytes { get; }
- ///
- /// The detected body type. Convenience getter for Handlebars.
- ///
- string DetectedBodyType { get; }
+ ///
+ /// The detected body type. Convenience getter for Handlebars.
+ ///
+ string DetectedBodyType { get; }
- ///
- /// The detected body type from the Content-Type header. Convenience getter for Handlebars.
- ///
- string DetectedBodyTypeFromContentType { get; }
+ ///
+ /// The detected body type from the Content-Type header. Convenience getter for Handlebars.
+ ///
+ string DetectedBodyTypeFromContentType { get; }
- ///
- /// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
- ///
- string DetectedCompression { get; }
+ ///
+ /// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
+ ///
+ string DetectedCompression { get; }
- ///
- /// Gets the Host
- ///
- string Host { get; }
+ ///
+ /// Gets the Host
+ ///
+ string Host { get; }
- ///
- /// Gets the protocol
- ///
- string Protocol { get; }
+ ///
+ /// Gets the protocol
+ ///
+ string Protocol { get; }
- ///
- /// Gets the port
- ///
- int Port { get; }
+ ///
+ /// Gets the port
+ ///
+ int Port { get; }
- ///
- /// Gets the origin
- ///
- string Origin { get; }
- }
+ ///
+ /// Gets the origin
+ ///
+ string Origin { get; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/IResponseMessage.cs b/src/WireMock.Net.Abstractions/IResponseMessage.cs
index b249171d..467edc88 100644
--- a/src/WireMock.Net.Abstractions/IResponseMessage.cs
+++ b/src/WireMock.Net.Abstractions/IResponseMessage.cs
@@ -38,7 +38,7 @@ namespace WireMock
///
/// Gets the headers.
///
- IDictionary> Headers { get; }
+ IDictionary>? Headers { get; }
///
/// Gets or sets the status code.
diff --git a/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatcher.cs b/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatcher.cs
index c3375d8f..cc2e904b 100644
--- a/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatcher.cs
+++ b/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatcher.cs
@@ -15,6 +15,6 @@ namespace WireMock.Matchers.Request
///
/// A value between 0.0 - 1.0 of the similarity.
///
- double GetMatchingScore([NotNull] IRequestMessage requestMessage, [NotNull] IRequestMatchResult requestMatchResult);
+ double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Models/IWebhookRequest.cs b/src/WireMock.Net.Abstractions/Models/IWebhookRequest.cs
index 0f6e9be5..caa6df46 100644
--- a/src/WireMock.Net.Abstractions/Models/IWebhookRequest.cs
+++ b/src/WireMock.Net.Abstractions/Models/IWebhookRequest.cs
@@ -22,12 +22,12 @@ namespace WireMock.Models
///
/// The Headers to send.
///
- IDictionary> Headers { get; }
+ IDictionary>? Headers { get; }
///
/// The body to send.
///
- IBodyData BodyData { get; set; }
+ IBodyData? BodyData { get; set; }
///
/// Use Transformer.
diff --git a/src/WireMock.Net.Matchers.CSharpCode/Matchers/CSharpCodeMatcher.cs b/src/WireMock.Net.Matchers.CSharpCode/Matchers/CSharpCodeMatcher.cs
index 9173b93a..d8eb739d 100644
--- a/src/WireMock.Net.Matchers.CSharpCode/Matchers/CSharpCodeMatcher.cs
+++ b/src/WireMock.Net.Matchers.CSharpCode/Matchers/CSharpCodeMatcher.cs
@@ -3,138 +3,137 @@ using System.Linq;
using System.Reflection;
using System.Text;
using AnyOfTypes;
-using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
+using Stef.Validation;
using WireMock.Exceptions;
using WireMock.Extensions;
using WireMock.Models;
-using Stef.Validation;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// CSharpCode / CS-Script Matcher
+///
+///
+internal class CSharpCodeMatcher : ICSharpCodeMatcher
{
- ///
- /// CSharpCode / CS-Script Matcher
- ///
- ///
- internal class CSharpCodeMatcher : ICSharpCodeMatcher
+ private const string TemplateForIsMatchWithString = "public class CodeHelper {{ public bool IsMatch(string it) {{ {0} }} }}";
+
+ private const string TemplateForIsMatchWithDynamic = "public class CodeHelper {{ public bool IsMatch(dynamic it) {{ {0} }} }}";
+
+ private readonly string[] _usings =
{
- private const string TemplateForIsMatchWithString = "public class CodeHelper {{ public bool IsMatch(string it) {{ {0} }} }}";
+ "System",
+ "System.Linq",
+ "System.Collections.Generic",
+ "Microsoft.CSharp",
+ "Newtonsoft.Json.Linq"
+ };
- private const string TemplateForIsMatchWithDynamic = "public class CodeHelper {{ public bool IsMatch(dynamic it) {{ {0} }} }}";
+ public MatchBehaviour MatchBehaviour { get; }
- private readonly string[] _usings =
- {
- "System",
- "System.Linq",
- "System.Collections.Generic",
- "Microsoft.CSharp",
- "Newtonsoft.Json.Linq"
- };
-
- public MatchBehaviour MatchBehaviour { get; }
-
- ///
- public bool ThrowException { get; }
-
- private readonly AnyOf[] _patterns;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The patterns.
- public CSharpCodeMatcher([NotNull] params AnyOf[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns)
+ ///
+ public bool ThrowException { get; }
+
+ private readonly AnyOf[] _patterns;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The patterns.
+ public CSharpCodeMatcher(params AnyOf[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// The to use. (default = "Or")
+ /// The patterns.
+ public CSharpCodeMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator = MatchOperator.Or, params AnyOf[] patterns)
+ {
+ _patterns = Guard.NotNull(patterns);
+ MatchBehaviour = matchBehaviour;
+ ThrowException = false;
+ MatchOperator = matchOperator;
+ }
+
+ public double IsMatch(string input)
+ {
+ return IsMatchInternal(input);
+ }
+
+ public double IsMatch(object? input)
+ {
+ return IsMatchInternal(input);
+ }
+
+ public double IsMatchInternal(object? input)
+ {
+ double match = MatchScores.Mismatch;
+
+ if (input != null)
{
+ match = MatchScores.ToScore(_patterns.Select(pattern => IsMatch(input, pattern.GetPattern())).ToArray(), MatchOperator);
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// The patterns.
- public CSharpCodeMatcher(MatchBehaviour matchBehaviour, [NotNull] params AnyOf[] patterns)
- {
- Guard.NotNull(patterns, nameof(patterns));
+ return MatchBehaviourHelper.Convert(MatchBehaviour, match);
+ }
- MatchBehaviour = matchBehaviour;
- ThrowException = false;
- _patterns = patterns;
- }
+ private bool IsMatch(dynamic input, string pattern)
+ {
+ bool isMatchWithString = input is string;
+ var inputValue = isMatchWithString ? input : JObject.FromObject(input);
+ string source = GetSourceForIsMatchWithString(pattern, isMatchWithString);
- public double IsMatch(string input)
- {
- return IsMatchInternal(input);
- }
-
- public double IsMatch(object input)
- {
- return IsMatchInternal(input);
- }
-
- public double IsMatchInternal(object input)
- {
- double match = MatchScores.Mismatch;
-
- if (input != null)
- {
- match = MatchScores.ToScore(_patterns.Select(pattern => IsMatch(input, pattern.GetPattern())));
- }
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, match);
- }
-
- private bool IsMatch(dynamic input, string pattern)
- {
- bool isMatchWithString = input is string;
- var inputValue = isMatchWithString ? input : JObject.FromObject(input);
- string source = GetSourceForIsMatchWithString(pattern, isMatchWithString);
-
- object result = null;
+ object? result;
#if (NET451 || NET452)
- var compilerParams = new System.CodeDom.Compiler.CompilerParameters
+ var compilerParams = new System.CodeDom.Compiler.CompilerParameters
+ {
+ GenerateInMemory = true,
+ GenerateExecutable = false,
+ ReferencedAssemblies =
{
- GenerateInMemory = true,
- GenerateExecutable = false,
- ReferencedAssemblies =
- {
- "System.dll",
- "System.Core.dll",
- "Microsoft.CSharp.dll",
- "Newtonsoft.Json.dll"
- }
- };
-
- using (var codeProvider = new Microsoft.CSharp.CSharpCodeProvider())
- {
- var compilerResults = codeProvider.CompileAssemblyFromSource(compilerParams, source);
-
- if (compilerResults.Errors.Count != 0)
- {
- var errors = from System.CodeDom.Compiler.CompilerError er in compilerResults.Errors select er.ToString();
- throw new WireMockException(string.Join(", ", errors));
- }
-
- object helper = compilerResults.CompiledAssembly.CreateInstance("CodeHelper");
- if (helper == null)
- {
- throw new WireMockException("CSharpCodeMatcher: Unable to create instance from WireMock.CodeHelper");
- }
-
- var methodInfo = helper.GetType().GetMethod("IsMatch");
- if (methodInfo == null)
- {
- throw new WireMockException("CSharpCodeMatcher: Unable to find method 'IsMatch' in WireMock.CodeHelper");
- }
-
- try
- {
- result = methodInfo.Invoke(helper, new[] { inputValue });
- }
- catch (Exception ex)
- {
- throw new WireMockException("CSharpCodeMatcher: Unable to call method 'IsMatch' in WireMock.CodeHelper", ex);
- }
+ "System.dll",
+ "System.Core.dll",
+ "Microsoft.CSharp.dll",
+ "Newtonsoft.Json.dll"
}
+ };
+
+ using (var codeProvider = new Microsoft.CSharp.CSharpCodeProvider())
+ {
+ var compilerResults = codeProvider.CompileAssemblyFromSource(compilerParams, source);
+
+ if (compilerResults.Errors.Count != 0)
+ {
+ var errors = from System.CodeDom.Compiler.CompilerError er in compilerResults.Errors select er.ToString();
+ throw new WireMockException(string.Join(", ", errors));
+ }
+
+ var helper = compilerResults.CompiledAssembly?.CreateInstance("CodeHelper");
+ if (helper == null)
+ {
+ throw new WireMockException("CSharpCodeMatcher: Unable to create instance from WireMock.CodeHelper");
+ }
+
+ var methodInfo = helper.GetType().GetMethod("IsMatch");
+ if (methodInfo == null)
+ {
+ throw new WireMockException("CSharpCodeMatcher: Unable to find method 'IsMatch' in WireMock.CodeHelper");
+ }
+
+ try
+ {
+ result = methodInfo.Invoke(helper, new[] { inputValue });
+ }
+ catch (Exception ex)
+ {
+ throw new WireMockException("CSharpCodeMatcher: Unable to call method 'IsMatch' in WireMock.CodeHelper", ex);
+ }
+ }
#elif (NET46 || NET461)
dynamic script;
try
@@ -169,11 +168,7 @@ namespace WireMock.Matchers
dynamic script;
try
{
-//#if NETSTANDARD2_0
-// script = csscript.GenericExtensions.CreateObject(assembly, "*");
-//#else
script = CSScripting.ReflectionExtensions.CreateObject(assembly, "*");
-//#endif
}
catch (Exception ex)
{
@@ -191,38 +186,40 @@ namespace WireMock.Matchers
#else
throw new NotSupportedException("The 'CSharpCodeMatcher' cannot be used in netstandard 1.3");
#endif
- try
- {
- return (bool)result;
- }
- catch
- {
- throw new WireMockException($"Unable to cast result '{result}' to bool");
- }
- }
-
- private string GetSourceForIsMatchWithString(string pattern, bool isMatchWithString)
+ try
{
- string template = isMatchWithString ? TemplateForIsMatchWithString : TemplateForIsMatchWithDynamic;
-
- var stringBuilder = new StringBuilder();
- foreach (string @using in _usings)
- {
- stringBuilder.AppendLine($"using {@using};");
- }
- stringBuilder.AppendLine();
- stringBuilder.AppendFormat(template, pattern);
-
- return stringBuilder.ToString();
+ return (bool)result;
}
-
- ///
- public AnyOf[] GetPatterns()
+ catch
{
- return _patterns;
+ throw new WireMockException($"Unable to cast result '{result}' to bool");
}
-
- ///
- public string Name => "CSharpCodeMatcher";
}
+
+ private string GetSourceForIsMatchWithString(string pattern, bool isMatchWithString)
+ {
+ string template = isMatchWithString ? TemplateForIsMatchWithString : TemplateForIsMatchWithDynamic;
+
+ var stringBuilder = new StringBuilder();
+ foreach (string @using in _usings)
+ {
+ stringBuilder.AppendLine($"using {@using};");
+ }
+ stringBuilder.AppendLine();
+ stringBuilder.AppendFormat(template, pattern);
+
+ return stringBuilder.ToString();
+ }
+
+ ///
+ public AnyOf[] GetPatterns()
+ {
+ return _patterns;
+ }
+
+ ///
+ public MatchOperator MatchOperator { get; }
+
+ ///
+ public string Name => "CSharpCodeMatcher";
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Authentication/AzureADAuthenticationMatcher.cs b/src/WireMock.Net/Authentication/AzureADAuthenticationMatcher.cs
index e8177f18..46b56705 100644
--- a/src/WireMock.Net/Authentication/AzureADAuthenticationMatcher.cs
+++ b/src/WireMock.Net/Authentication/AzureADAuthenticationMatcher.cs
@@ -39,6 +39,8 @@ namespace WireMock.Authentication
return new AnyOf[0];
}
+ public MatchOperator MatchOperator { get; } = MatchOperator.Or;
+
public double IsMatch(string input)
{
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase);
diff --git a/src/WireMock.Net/Http/HttpClientBuilder.cs b/src/WireMock.Net/Http/HttpClientBuilder.cs
index 5b270c35..70142cc2 100644
--- a/src/WireMock.Net/Http/HttpClientBuilder.cs
+++ b/src/WireMock.Net/Http/HttpClientBuilder.cs
@@ -3,64 +3,63 @@ using System.Net.Http;
using WireMock.HttpsCertificate;
using WireMock.Settings;
-namespace WireMock.Http
+namespace WireMock.Http;
+
+internal static class HttpClientBuilder
{
- internal static class HttpClientBuilder
+ public static HttpClient Build(HttpClientSettings settings)
{
- public static HttpClient Build(HttpClientSettings settings)
- {
#if NETSTANDARD || NETCOREAPP3_1 || NET5_0 || NET6_0
- var handler = new HttpClientHandler
- {
- CheckCertificateRevocationList = false,
- SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
- ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
- AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
- };
+ var handler = new HttpClientHandler
+ {
+ CheckCertificateRevocationList = false,
+ SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
+ ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
+ AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
+ };
#elif NET46
- var handler = new HttpClientHandler
- {
- ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
- AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
- };
+ var handler = new HttpClientHandler
+ {
+ ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true,
+ AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
+ };
#else
- var handler = new WebRequestHandler
- {
- ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
- AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
- };
+ var handler = new WebRequestHandler
+ {
+ ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true,
+ AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
+ };
#endif
- if (!string.IsNullOrEmpty(settings.ClientX509Certificate2ThumbprintOrSubjectName))
+ if (!string.IsNullOrEmpty(settings.ClientX509Certificate2ThumbprintOrSubjectName))
+ {
+ handler.ClientCertificateOptions = ClientCertificateOption.Manual;
+
+ var x509Certificate2 = CertificateLoader.LoadCertificate(settings.ClientX509Certificate2ThumbprintOrSubjectName);
+ handler.ClientCertificates.Add(x509Certificate2);
+ }
+
+ handler.AllowAutoRedirect = settings.AllowAutoRedirect == true;
+
+ // If UseCookies enabled, httpClient ignores Cookie header
+ handler.UseCookies = false;
+
+ if (settings.WebProxySettings != null)
+ {
+ handler.UseProxy = true;
+
+ handler.Proxy = new WebProxy(settings.WebProxySettings.Address);
+ if (settings.WebProxySettings.UserName != null && settings.WebProxySettings.Password != null)
{
- handler.ClientCertificateOptions = ClientCertificateOption.Manual;
-
- var x509Certificate2 = CertificateLoader.LoadCertificate(settings.ClientX509Certificate2ThumbprintOrSubjectName);
- handler.ClientCertificates.Add(x509Certificate2);
- }
-
- handler.AllowAutoRedirect = settings.AllowAutoRedirect == true;
-
- // If UseCookies enabled, httpClient ignores Cookie header
- handler.UseCookies = false;
-
- if (settings.WebProxySettings != null)
- {
- handler.UseProxy = true;
-
- handler.Proxy = new WebProxy(settings.WebProxySettings.Address);
- if (settings.WebProxySettings.UserName != null && settings.WebProxySettings.Password != null)
- {
- handler.Proxy.Credentials = new NetworkCredential(settings.WebProxySettings.UserName, settings.WebProxySettings.Password);
- }
+ handler.Proxy.Credentials = new NetworkCredential(settings.WebProxySettings.UserName, settings.WebProxySettings.Password);
}
+ }
#if !NETSTANDARD1_3
- ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
- ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;
+ ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
+ ServicePointManager.ServerCertificateValidationCallback = (message, cert, chain, errors) => true;
#endif
- return new HttpClient(handler);
- }
+ return HttpClientFactory2.Create(handler);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Http/HttpClientFactory2.cs b/src/WireMock.Net/Http/HttpClientFactory2.cs
new file mode 100644
index 00000000..03690172
--- /dev/null
+++ b/src/WireMock.Net/Http/HttpClientFactory2.cs
@@ -0,0 +1,24 @@
+using System.Net.Http;
+
+namespace WireMock.Http;
+
+internal static class HttpClientFactory2
+{
+ public static HttpClient Create(params DelegatingHandler[] handlers)
+ {
+#if NETSTANDARD1_3
+ return new HttpClient();
+#else
+ return HttpClientFactory.Create(handlers);
+#endif
+ }
+
+ public static HttpClient Create(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers)
+ {
+#if NETSTANDARD1_3
+ return new HttpClient(innerHandler);
+#else
+ return HttpClientFactory.Create(innerHandler, handlers);
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Http/WebhookSender.cs b/src/WireMock.Net/Http/WebhookSender.cs
index 628807a1..cf3d9272 100644
--- a/src/WireMock.Net/Http/WebhookSender.cs
+++ b/src/WireMock.Net/Http/WebhookSender.cs
@@ -26,15 +26,15 @@ namespace WireMock.Http
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
}
- public Task SendAsync([NotNull] HttpClient client, [NotNull] IWebhookRequest request, [NotNull] IRequestMessage originalRequestMessage, [NotNull] IResponseMessage originalResponseMessage)
+ public Task SendAsync(HttpClient client, IWebhookRequest request, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage)
{
- Guard.NotNull(client, nameof(client));
- Guard.NotNull(request, nameof(request));
- Guard.NotNull(originalRequestMessage, nameof(originalRequestMessage));
- Guard.NotNull(originalResponseMessage, nameof(originalResponseMessage));
+ Guard.NotNull(client);
+ Guard.NotNull(request);
+ Guard.NotNull(originalRequestMessage);
+ Guard.NotNull(originalResponseMessage);
- IBodyData bodyData;
- IDictionary> headers;
+ IBodyData? bodyData;
+ IDictionary>? headers;
if (request.UseTransformer == true)
{
ITransformer responseMessageTransformer;
diff --git a/src/WireMock.Net/IMapping.cs b/src/WireMock.Net/IMapping.cs
index e088cf91..b49dfa93 100644
--- a/src/WireMock.Net/IMapping.cs
+++ b/src/WireMock.Net/IMapping.cs
@@ -1,4 +1,3 @@
-using JetBrains.Annotations;
using System;
using System.Threading.Tasks;
using WireMock.Matchers.Request;
@@ -6,130 +5,125 @@ using WireMock.Models;
using WireMock.ResponseProviders;
using WireMock.Settings;
-namespace WireMock
+namespace WireMock;
+
+///
+/// The IMapping interface.
+///
+public interface IMapping
{
///
- /// The IMapping interface.
+ /// Gets the unique identifier.
///
- public interface IMapping
- {
- ///
- /// Gets the unique identifier.
- ///
- Guid Guid { get; }
+ Guid Guid { get; }
- ///
- /// Gets the TimeSettings (Start, End and TTL).
- ///
- ITimeSettings TimeSettings { get; }
+ ///
+ /// Gets the TimeSettings (Start, End and TTL).
+ ///
+ ITimeSettings TimeSettings { get; }
- ///
- /// Gets the unique title.
- ///
- string Title { get; }
+ ///
+ /// Gets the unique title.
+ ///
+ string Title { get; }
- ///
- /// Gets the description.
- ///
- string Description { get; }
+ ///
+ /// Gets the description.
+ ///
+ string Description { get; }
- ///
- /// The full filename path for this mapping (only defined for static mappings).
- ///
- string Path { get; set; }
+ ///
+ /// The full filename path for this mapping (only defined for static mappings).
+ ///
+ string Path { get; set; }
- ///
- /// Gets the priority. (A low value means higher priority.)
- ///
- int Priority { get; }
+ ///
+ /// Gets the priority. (A low value means higher priority.)
+ ///
+ int Priority { get; }
- ///
- /// Scenario.
- ///
- [CanBeNull]
- string Scenario { get; }
+ ///
+ /// Scenario.
+ ///
+ string? Scenario { get; }
- ///
- /// Execution state condition for the current mapping.
- ///
- [CanBeNull]
- string ExecutionConditionState { get; }
+ ///
+ /// Execution state condition for the current mapping.
+ ///
+ string? ExecutionConditionState { get; }
- ///
- /// The next state which will be signaled after the current mapping execution.
- /// In case the value is null, state will not be changed.
- ///
- [CanBeNull]
- string NextState { get; }
+ ///
+ /// The next state which will be signaled after the current mapping execution.
+ /// In case the value is null, state will not be changed.
+ ///
+ string? NextState { get; }
- ///
- /// The number of times this match should be matched before the state will be changed to the next state.
- ///
- [CanBeNull]
- int? StateTimes { get; }
+ ///
+ /// The number of times this match should be matched before the state will be changed to the next state.
+ ///
+ int? StateTimes { get; }
- ///
- /// The Request matcher.
- ///
- IRequestMatcher RequestMatcher { get; }
+ ///
+ /// The Request matcher.
+ ///
+ IRequestMatcher RequestMatcher { get; }
- ///
- /// The Provider.
- ///
- IResponseProvider Provider { get; }
+ ///
+ /// The Provider.
+ ///
+ IResponseProvider Provider { get; }
- ///
- /// The WireMockServerSettings.
- ///
- WireMockServerSettings Settings { get; }
+ ///
+ /// The WireMockServerSettings.
+ ///
+ WireMockServerSettings Settings { get; }
- ///
- /// Is State started ?
- ///
- bool IsStartState { get; }
+ ///
+ /// Is State started ?
+ ///
+ bool IsStartState { get; }
- ///
- /// Gets a value indicating whether this mapping is an Admin Interface.
- ///
- ///
- /// true if this mapping is an Admin Interface; otherwise, false.
- ///
- bool IsAdminInterface { get; }
+ ///
+ /// Gets a value indicating whether this mapping is an Admin Interface.
+ ///
+ ///
+ /// true if this mapping is an Admin Interface; otherwise, false.
+ ///
+ bool IsAdminInterface { get; }
- ///
- /// Gets a value indicating whether this mapping is a Proxy Mapping.
- ///
- ///
- /// true if this mapping is a Proxy Mapping; otherwise, false.
- ///
- bool IsProxy { get; }
+ ///
+ /// Gets a value indicating whether this mapping is a Proxy Mapping.
+ ///
+ ///
+ /// true if this mapping is a Proxy Mapping; otherwise, false.
+ ///
+ bool IsProxy { get; }
- ///
- /// Gets a value indicating whether this mapping to be logged.
- ///
- ///
- /// true if this mapping to be logged; otherwise, false.
- ///
- bool LogMapping { get; }
+ ///
+ /// Gets a value indicating whether this mapping to be logged.
+ ///
+ ///
+ /// true if this mapping to be logged; otherwise, false.
+ ///
+ bool LogMapping { get; }
- ///
- /// The Webhooks.
- ///
- IWebhook[] Webhooks { get; }
+ ///
+ /// The Webhooks.
+ ///
+ IWebhook[]? Webhooks { get; }
- ///
- /// ProvideResponseAsync
- ///
- /// The request message.
- /// The including a new (optional) .
- Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage);
+ ///
+ /// ProvideResponseAsync
+ ///
+ /// The request message.
+ /// The including a new (optional) .
+ Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage);
- ///
- /// Gets the RequestMatchResult based on the RequestMessage.
- ///
- /// The request message.
- /// The Next State.
- /// The .
- IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, [CanBeNull] string nextState);
- }
+ ///
+ /// Gets the RequestMatchResult based on the RequestMessage.
+ ///
+ /// The request message.
+ /// The Next State.
+ /// The .
+ IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string? nextState);
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/AbstractJsonPartialMatcher.cs b/src/WireMock.Net/Matchers/AbstractJsonPartialMatcher.cs
index 70d610f1..2f3fb27a 100644
--- a/src/WireMock.Net/Matchers/AbstractJsonPartialMatcher.cs
+++ b/src/WireMock.Net/Matchers/AbstractJsonPartialMatcher.cs
@@ -1,89 +1,87 @@
using System.Collections.Generic;
using System.Linq;
-using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// Generic AbstractJsonPartialMatcher
+///
+public abstract class AbstractJsonPartialMatcher : JsonMatcher
{
///
- /// Generic AbstractJsonPartialMatcher
+ /// Initializes a new instance of the class.
///
- public abstract class AbstractJsonPartialMatcher : JsonMatcher
+ /// The string value to check for equality.
+ /// Ignore the case from the PropertyName and PropertyValue (string only).
+ /// Throw an exception when the internal matching fails because of invalid input.
+ protected AbstractJsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false)
+ : base(value, ignoreCase, throwException)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The string value to check for equality.
- /// Ignore the case from the PropertyName and PropertyValue (string only).
- /// Throw an exception when the internal matching fails because of invalid input.
- protected AbstractJsonPartialMatcher([NotNull] string value, bool ignoreCase = false, bool throwException = false)
- : base(value, ignoreCase, throwException)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The object value to check for equality.
- /// Ignore the case from the PropertyName and PropertyValue (string only).
- /// Throw an exception when the internal matching fails because of invalid input.
- protected AbstractJsonPartialMatcher([NotNull] object value, bool ignoreCase = false, bool throwException = false)
- : base(value, ignoreCase, throwException)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// The value to check for equality.
- /// Ignore the case from the PropertyName and PropertyValue (string only).
- /// Throw an exception when the internal matching fails because of invalid input.
- protected AbstractJsonPartialMatcher(MatchBehaviour matchBehaviour, [NotNull] object value, bool ignoreCase = false, bool throwException = false)
- : base(matchBehaviour, value, ignoreCase, throwException)
- {
- }
-
- ///
- protected override bool IsMatch(JToken value, JToken input)
- {
- if (value == null || value == input)
- {
- return true;
- }
-
- if (input == null || value.Type != input.Type)
- {
- return false;
- }
-
- switch (value.Type)
- {
- case JTokenType.Object:
- var nestedValues = value.ToObject>();
- return nestedValues?.Any() != true ||
- nestedValues.All(pair => IsMatch(pair.Value, input.SelectToken(pair.Key)));
-
- case JTokenType.Array:
- var valuesArray = value.ToObject();
- var tokenArray = input.ToObject();
-
- if (valuesArray?.Any() != true)
- {
- return true;
- }
-
- return tokenArray?.Any() == true &&
- valuesArray.All(subFilter => tokenArray.Any(subToken => IsMatch(subFilter, subToken)));
-
- default:
- return IsMatch(value.ToString(), input.ToString());
- }
- }
-
- ///
- /// Check if two strings are a match (matching can be done exact or wildcard)
- ///
- protected abstract bool IsMatch(string value, string input);
}
-}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The object value to check for equality.
+ /// Ignore the case from the PropertyName and PropertyValue (string only).
+ /// Throw an exception when the internal matching fails because of invalid input.
+ protected AbstractJsonPartialMatcher(object value, bool ignoreCase = false, bool throwException = false)
+ : base(value, ignoreCase, throwException)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// The value to check for equality.
+ /// Ignore the case from the PropertyName and PropertyValue (string only).
+ /// Throw an exception when the internal matching fails because of invalid input.
+ protected AbstractJsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false)
+ : base(matchBehaviour, value, ignoreCase, throwException)
+ {
+ }
+
+ ///
+ protected override bool IsMatch(JToken? value, JToken? input)
+ {
+ if (value == null || value == input)
+ {
+ return true;
+ }
+
+ if (input == null || value.Type != input.Type)
+ {
+ return false;
+ }
+
+ switch (value.Type)
+ {
+ case JTokenType.Object:
+ var nestedValues = value.ToObject>();
+ return nestedValues?.Any() != true ||
+ nestedValues.All(pair => IsMatch(pair.Value, input.SelectToken(pair.Key)));
+
+ case JTokenType.Array:
+ var valuesArray = value.ToObject();
+ var tokenArray = input.ToObject();
+
+ if (valuesArray?.Any() != true)
+ {
+ return true;
+ }
+
+ return tokenArray?.Any() == true &&
+ valuesArray.All(subFilter => tokenArray.Any(subToken => IsMatch(subFilter, subToken)));
+
+ default:
+ return IsMatch(value.ToString(), input.ToString());
+ }
+ }
+
+ ///
+ /// Check if two strings are a match (matching can be done exact or wildcard)
+ ///
+ protected abstract bool IsMatch(string value, string input);
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/ContentTypeMatcher.cs b/src/WireMock.Net/Matchers/ContentTypeMatcher.cs
index d4ac069e..a5d21a82 100644
--- a/src/WireMock.Net/Matchers/ContentTypeMatcher.cs
+++ b/src/WireMock.Net/Matchers/ContentTypeMatcher.cs
@@ -3,75 +3,74 @@ using AnyOfTypes;
using JetBrains.Annotations;
using WireMock.Models;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// ContentTypeMatcher which accepts also all charsets
+///
+///
+public class ContentTypeMatcher : WildcardMatcher
{
+ private readonly AnyOf[] _patterns;
+
///
- /// ContentTypeMatcher which accepts also all charsets
+ /// Initializes a new instance of the class.
///
- ///
- public class ContentTypeMatcher : WildcardMatcher
+ /// The pattern.
+ /// IgnoreCase (default false)
+ public ContentTypeMatcher([NotNull] AnyOf pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
{
- private readonly AnyOf[] _patterns;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The pattern.
- /// IgnoreCase (default false)
- public ContentTypeMatcher([NotNull] AnyOf pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// The pattern.
- /// IgnoreCase (default false)
- public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] AnyOf pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The patterns.
- /// IgnoreCase (default false)
- public ContentTypeMatcher([NotNull] AnyOf[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// The patterns.
- /// IgnoreCase (default false)
- /// Throw an exception when the internal matching fails because of invalid input.
- public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] AnyOf[] patterns, bool ignoreCase = false, bool throwException = false) :
- base(matchBehaviour, patterns, ignoreCase, throwException)
- {
- _patterns = patterns;
- }
-
- ///
- public override double IsMatch(string input)
- {
- if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out MediaTypeHeaderValue contentType))
- {
- return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
- }
-
- return base.IsMatch(contentType.MediaType);
- }
-
- ///
- public override AnyOf[] GetPatterns()
- {
- return _patterns;
- }
-
- ///
- public override string Name => "ContentTypeMatcher";
}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// The pattern.
+ /// IgnoreCase (default false)
+ public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] AnyOf pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The patterns.
+ /// IgnoreCase (default false)
+ public ContentTypeMatcher(AnyOf[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// The patterns.
+ /// IgnoreCase (default false)
+ /// Throw an exception when the internal matching fails because of invalid input.
+ public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf[] patterns, bool ignoreCase = false, bool throwException = false) :
+ base(matchBehaviour, patterns, ignoreCase, throwException)
+ {
+ _patterns = patterns;
+ }
+
+ ///
+ public override double IsMatch(string? input)
+ {
+ if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out MediaTypeHeaderValue contentType))
+ {
+ return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
+ }
+
+ return base.IsMatch(contentType.MediaType);
+ }
+
+ ///
+ public override AnyOf[] GetPatterns()
+ {
+ return _patterns;
+ }
+
+ ///
+ public override string Name => "ContentTypeMatcher";
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/ExactMatcher.cs b/src/WireMock.Net/Matchers/ExactMatcher.cs
index e9f301e7..70fb1c92 100644
--- a/src/WireMock.Net/Matchers/ExactMatcher.cs
+++ b/src/WireMock.Net/Matchers/ExactMatcher.cs
@@ -1,67 +1,69 @@
using System.Linq;
using AnyOfTypes;
-using JetBrains.Annotations;
+using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
-using Stef.Validation;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// ExactMatcher
+///
+///
+public class ExactMatcher : IStringMatcher
{
+ private readonly AnyOf[] _values;
+
+ ///
+ public MatchBehaviour MatchBehaviour { get; }
+
+ ///
+ public bool ThrowException { get; }
+
///
- /// ExactMatcher
+ /// Initializes a new instance of the class.
///
- ///
- public class ExactMatcher : IStringMatcher
+ /// The values.
+ public ExactMatcher(params AnyOf[] values) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, values)
{
- private readonly AnyOf[] _values;
-
- ///
- public MatchBehaviour MatchBehaviour { get; }
-
- ///
- public bool ThrowException { get; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The values.
- public ExactMatcher([NotNull] params AnyOf[] values) : this(MatchBehaviour.AcceptOnMatch, false, values)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// Throw an exception when the internal matching fails because of invalid input.
- /// The values.
- public ExactMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params AnyOf[] values)
- {
- Guard.NotNull(values, nameof(values));
-
- MatchBehaviour = matchBehaviour;
- ThrowException = throwException;
- _values = values;
- }
-
- ///
- public double IsMatch(string input)
- {
- if (_values.Length == 1)
- {
- return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_values[0].GetPattern() == input));
- }
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_values.Select(v => v.GetPattern()).Contains(input)));
- }
-
- ///
- public AnyOf[] GetPatterns()
- {
- return _values;
- }
-
- ///
- public string Name => "ExactMatcher";
}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// Throw an exception when the internal matching fails because of invalid input.
+ /// The to use. (default = "Or")
+ /// The values.
+ public ExactMatcher(
+ MatchBehaviour matchBehaviour,
+ bool throwException = false,
+ MatchOperator matchOperator = MatchOperator.Or,
+ params AnyOf[] values)
+ {
+ _values = Guard.NotNull(values);
+
+ MatchBehaviour = matchBehaviour;
+ ThrowException = throwException;
+ MatchOperator = matchOperator;
+ }
+
+ ///
+ public double IsMatch(string? input)
+ {
+ double score = MatchScores.ToScore(_values.Select(v => v.GetPattern() == input).ToArray(), MatchOperator);
+ return MatchBehaviourHelper.Convert(MatchBehaviour, score);
+ }
+
+ ///
+ public AnyOf[] GetPatterns()
+ {
+ return _values;
+ }
+
+ ///
+ public MatchOperator MatchOperator { get; }
+
+ ///
+ public string Name => "ExactMatcher";
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/ExactObjectMatcher.cs b/src/WireMock.Net/Matchers/ExactObjectMatcher.cs
index fe116668..8b4e3786 100644
--- a/src/WireMock.Net/Matchers/ExactObjectMatcher.cs
+++ b/src/WireMock.Net/Matchers/ExactObjectMatcher.cs
@@ -1,83 +1,86 @@
-using JetBrains.Annotations;
using System.Linq;
using Stef.Validation;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// ExactObjectMatcher
+///
+///
+public class ExactObjectMatcher : IObjectMatcher
{
///
- /// ExactObjectMatcher
+ /// Gets the value as object.
///
- ///
- public class ExactObjectMatcher : IObjectMatcher
+ public object? ValueAsObject { get; }
+
+ ///
+ /// Gets the value as byte[].
+ ///
+ public byte[]? ValueAsBytes { get; }
+
+ ///
+ public MatchBehaviour MatchBehaviour { get; }
+
+ ///
+ public bool ThrowException { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value.
+ public ExactObjectMatcher(object value) : this(MatchBehaviour.AcceptOnMatch, value)
{
- ///
- /// Gets the value as object.
- ///
- public object ValueAsObject { get; }
-
- ///
- /// Gets the value as byte[].
- ///
- public byte[] ValueAsBytes { get; }
-
- ///
- public MatchBehaviour MatchBehaviour { get; }
-
- ///
- public bool ThrowException { get; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The value.
- public ExactObjectMatcher([NotNull] object value) : this(MatchBehaviour.AcceptOnMatch, value)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// The value.
- public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] object value)
- {
- Guard.NotNull(value, nameof(value));
-
- ValueAsObject = value;
- MatchBehaviour = matchBehaviour;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The value.
- public ExactObjectMatcher([NotNull] byte[] value) : this(MatchBehaviour.AcceptOnMatch, value)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// Throw an exception when the internal matching fails because of invalid input.
- /// The value.
- public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] value, bool throwException = false)
- {
- Guard.NotNull(value, nameof(value));
-
- MatchBehaviour = matchBehaviour;
- ThrowException = throwException;
- ValueAsBytes = value;
- }
-
- ///
- public double IsMatch(object input)
- {
- bool equals = ValueAsObject != null ? Equals(ValueAsObject, input) : ValueAsBytes.SequenceEqual((byte[])input);
- return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
- }
-
- ///
- public string Name => "ExactObjectMatcher";
}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// The value.
+ public ExactObjectMatcher(MatchBehaviour matchBehaviour, object value)
+ {
+ ValueAsObject = Guard.NotNull(value);
+ MatchBehaviour = matchBehaviour;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value.
+ public ExactObjectMatcher(byte[] value) : this(MatchBehaviour.AcceptOnMatch, value)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// Throw an exception when the internal matching fails because of invalid input.
+ /// The value.
+ public ExactObjectMatcher(MatchBehaviour matchBehaviour, byte[] value, bool throwException = false)
+ {
+ ValueAsBytes = Guard.NotNull(value);
+ MatchBehaviour = matchBehaviour;
+ ThrowException = throwException;
+ }
+
+ ///
+ public double IsMatch(object? input)
+ {
+ bool equals = false;
+ if (ValueAsObject != null)
+ {
+ equals = Equals(ValueAsObject, input);
+ }
+ else if (input != null)
+ {
+ equals = ValueAsBytes?.SequenceEqual((byte[])input) == true;
+ }
+
+ return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
+ }
+
+ ///
+ public string Name => "ExactObjectMatcher";
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/IObjectMatcher.cs b/src/WireMock.Net/Matchers/IObjectMatcher.cs
index 883e246d..233782a9 100644
--- a/src/WireMock.Net/Matchers/IObjectMatcher.cs
+++ b/src/WireMock.Net/Matchers/IObjectMatcher.cs
@@ -1,4 +1,4 @@
-namespace WireMock.Matchers
+namespace WireMock.Matchers
{
///
/// IObjectMatcher
@@ -10,6 +10,6 @@
///
/// The input.
/// A value between 0.0 - 1.0 of the similarity.
- double IsMatch(object input);
+ double IsMatch(object? input);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/IStringMatcher.cs b/src/WireMock.Net/Matchers/IStringMatcher.cs
index 126373fe..bf815eee 100644
--- a/src/WireMock.Net/Matchers/IStringMatcher.cs
+++ b/src/WireMock.Net/Matchers/IStringMatcher.cs
@@ -1,25 +1,29 @@
using AnyOfTypes;
using WireMock.Models;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// IStringMatcher
+///
+///
+public interface IStringMatcher : IMatcher
{
///
- /// IStringMatcher
+ /// Determines whether the specified input is match.
///
- ///
- public interface IStringMatcher : IMatcher
- {
- ///
- /// Determines whether the specified input is match.
- ///
- /// The input.
- /// A value between 0.0 - 1.0 of the similarity.
- double IsMatch(string input);
+ /// The input.
+ /// A value between 0.0 - 1.0 of the similarity.
+ double IsMatch(string? input);
- ///
- /// Gets the patterns.
- ///
- /// Patterns
- AnyOf[] GetPatterns();
- }
+ ///
+ /// Gets the patterns.
+ ///
+ /// Patterns
+ AnyOf[] GetPatterns();
+
+ ///
+ /// The .
+ ///
+ MatchOperator MatchOperator { get; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/JSONPathMatcher.cs b/src/WireMock.Net/Matchers/JSONPathMatcher.cs
index ba951d52..1e6be6f5 100644
--- a/src/WireMock.Net/Matchers/JSONPathMatcher.cs
+++ b/src/WireMock.Net/Matchers/JSONPathMatcher.cs
@@ -1,121 +1,126 @@
using System.Linq;
using AnyOfTypes;
-using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
-using Stef.Validation;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// JsonPathMatcher
+///
+///
+///
+public class JsonPathMatcher : IStringMatcher, IObjectMatcher
{
+ private readonly AnyOf[] _patterns;
+
+ ///
+ public MatchBehaviour MatchBehaviour { get; }
+
+ ///
+ public bool ThrowException { get; }
+
///
- /// JsonPathMatcher
+ /// Initializes a new instance of the class.
///
- ///
- ///
- public class JsonPathMatcher : IStringMatcher, IObjectMatcher
+ /// The patterns.
+ public JsonPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns.ToAnyOfPatterns())
{
- private readonly AnyOf[] _patterns;
+ }
- ///
- public MatchBehaviour MatchBehaviour { get; }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The patterns.
+ public JsonPathMatcher(params AnyOf[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns)
+ {
+ }
- ///
- public bool ThrowException { get; }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// Throw an exception when the internal matching fails because of invalid input.
+ /// The to use. (default = "Or")
+ /// The patterns.
+ public JsonPathMatcher(
+ MatchBehaviour matchBehaviour,
+ bool throwException = false,
+ MatchOperator matchOperator = MatchOperator.Or,
+ params AnyOf[] patterns)
+ {
+ _patterns = Guard.NotNull(patterns);
+ MatchBehaviour = matchBehaviour;
+ ThrowException = throwException;
+ MatchOperator = matchOperator;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// The patterns.
- public JsonPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns.ToAnyOfPatterns())
+ ///
+ public double IsMatch(string? input)
+ {
+ double match = MatchScores.Mismatch;
+ if (input != null)
{
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The patterns.
- public JsonPathMatcher([NotNull] params AnyOf[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// Throw an exception when the internal matching fails because of invalid input.
- /// The patterns.
- public JsonPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params AnyOf[] patterns)
- {
- Guard.NotNull(patterns, nameof(patterns));
-
- MatchBehaviour = matchBehaviour;
- ThrowException = throwException;
- _patterns = patterns;
- }
-
- ///
- public double IsMatch(string input)
- {
- double match = MatchScores.Mismatch;
- if (input != null)
+ try
{
- try
+ var jToken = JToken.Parse(input);
+ match = IsMatch(jToken);
+ }
+ catch (JsonException)
+ {
+ if (ThrowException)
{
- var jToken = JToken.Parse(input);
- match = IsMatch(jToken);
- }
- catch (JsonException)
- {
- if (ThrowException)
- {
- throw;
- }
+ throw;
}
}
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
- ///
- public double IsMatch(object input)
- {
- double match = MatchScores.Mismatch;
+ return MatchBehaviourHelper.Convert(MatchBehaviour, match);
+ }
- // When input is null or byte[], return Mismatch.
- if (input != null && !(input is byte[]))
+ ///
+ public double IsMatch(object? input)
+ {
+ double match = MatchScores.Mismatch;
+
+ // When input is null or byte[], return Mismatch.
+ if (input != null && !(input is byte[]))
+ {
+ try
{
- try
+ // Check if JToken or object
+ JToken jToken = input as JToken ?? JObject.FromObject(input);
+ match = IsMatch(jToken);
+ }
+ catch (JsonException)
+ {
+ if (ThrowException)
{
- // Check if JToken or object
- JToken jToken = input is JToken token ? token : JObject.FromObject(input);
- match = IsMatch(jToken);
- }
- catch (JsonException)
- {
- if (ThrowException)
- {
- throw;
- }
+ throw;
}
}
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
- ///
- public AnyOf[] GetPatterns()
- {
- return _patterns;
- }
+ return MatchBehaviourHelper.Convert(MatchBehaviour, match);
+ }
- ///
- public string Name => "JsonPathMatcher";
+ ///
+ public AnyOf[] GetPatterns()
+ {
+ return _patterns;
+ }
- private double IsMatch(JToken jToken)
- {
- return MatchScores.ToScore(_patterns.Select(pattern => jToken.SelectToken(pattern.GetPattern()) != null));
- }
+ ///
+ public MatchOperator MatchOperator { get; }
+
+ ///
+ public string Name => "JsonPathMatcher";
+
+ private double IsMatch(JToken jToken)
+ {
+ return MatchScores.ToScore(_patterns.Select(pattern => jToken.SelectToken(pattern.GetPattern()) != null).ToArray(), MatchOperator);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/JmesPathMatcher.cs b/src/WireMock.Net/Matchers/JmesPathMatcher.cs
index 41e8117a..84ad7925 100644
--- a/src/WireMock.Net/Matchers/JmesPathMatcher.cs
+++ b/src/WireMock.Net/Matchers/JmesPathMatcher.cs
@@ -1,11 +1,10 @@
+using System.Linq;
using AnyOfTypes;
using DevLab.JmesPath;
-using JetBrains.Annotations;
using Newtonsoft.Json;
-using System.Linq;
+using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
-using Stef.Validation;
namespace WireMock.Matchers
{
@@ -26,7 +25,7 @@ namespace WireMock.Matchers
/// Initializes a new instance of the class.
///
/// The patterns.
- public JmesPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns.ToAnyOfPatterns())
+ public JmesPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns.ToAnyOfPatterns())
{
}
@@ -34,7 +33,7 @@ namespace WireMock.Matchers
/// Initializes a new instance of the class.
///
/// The patterns.
- public JmesPathMatcher([NotNull] params AnyOf[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
+ public JmesPathMatcher(params AnyOf[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns)
{
}
@@ -42,8 +41,10 @@ namespace WireMock.Matchers
/// Initializes a new instance of the class.
///
/// Throw an exception when the internal matching fails because of invalid input.
+ /// The to use.
/// The patterns.
- public JmesPathMatcher(bool throwException = false, [NotNull] params AnyOf[] patterns) : this(MatchBehaviour.AcceptOnMatch, throwException, patterns)
+ public JmesPathMatcher(bool throwException = false, MatchOperator matchOperator = MatchOperator.Or, params AnyOf[] patterns) :
+ this(MatchBehaviour.AcceptOnMatch, throwException, matchOperator, patterns)
{
}
@@ -52,25 +53,30 @@ namespace WireMock.Matchers
///
/// The match behaviour.
/// Throw an exception when the internal matching fails because of invalid input.
+ /// The to use.
/// The patterns.
- public JmesPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params AnyOf[] patterns)
+ public JmesPathMatcher(
+ MatchBehaviour matchBehaviour,
+ bool throwException = false,
+ MatchOperator matchOperator = MatchOperator.Or,
+ params AnyOf[] patterns)
{
- Guard.NotNull(patterns, nameof(patterns));
-
+ _patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
- _patterns = patterns;
+ MatchOperator = matchOperator;
}
///
- public double IsMatch(string input)
+ public double IsMatch(string? input)
{
double match = MatchScores.Mismatch;
if (input != null)
{
try
{
- match = MatchScores.ToScore(_patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern.GetPattern()))));
+ var results = _patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern.GetPattern()))).ToArray();
+ match = MatchScores.ToScore(results, MatchOperator);
}
catch (JsonException)
{
@@ -85,7 +91,7 @@ namespace WireMock.Matchers
}
///
- public double IsMatch(object input)
+ public double IsMatch(object? input)
{
double match = MatchScores.Mismatch;
@@ -105,6 +111,9 @@ namespace WireMock.Matchers
return _patterns;
}
+ ///
+ public MatchOperator MatchOperator { get; }
+
///
public string Name => "JmesPathMatcher";
}
diff --git a/src/WireMock.Net/Matchers/JsonMatcher.cs b/src/WireMock.Net/Matchers/JsonMatcher.cs
index eed4a542..28810b2e 100644
--- a/src/WireMock.Net/Matchers/JsonMatcher.cs
+++ b/src/WireMock.Net/Matchers/JsonMatcher.cs
@@ -6,164 +6,163 @@ using Newtonsoft.Json.Linq;
using Stef.Validation;
using WireMock.Util;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// JsonMatcher
+///
+public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
{
+ ///
+ public object Value { get; }
+
+ ///
+ public virtual string Name => "JsonMatcher";
+
+ ///
+ public MatchBehaviour MatchBehaviour { get; }
+
+ ///
+ public bool IgnoreCase { get; }
+
+ ///
+ public bool ThrowException { get; }
+
+ private readonly JToken _valueAsJToken;
+ private readonly Func _jTokenConverter;
+
///
- /// JsonMatcher
+ /// Initializes a new instance of the class.
///
- public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
+ /// The string value to check for equality.
+ /// Ignore the case from the PropertyName and PropertyValue (string only).
+ /// Throw an exception when the internal matching fails because of invalid input.
+ public JsonMatcher(string value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
{
- ///
- public object Value { get; }
+ }
- ///
- public virtual string Name => "JsonMatcher";
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The object value to check for equality.
+ /// Ignore the case from the PropertyName and PropertyValue (string only).
+ /// Throw an exception when the internal matching fails because of invalid input.
+ public JsonMatcher(object value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
+ {
+ }
- ///
- public MatchBehaviour MatchBehaviour { get; }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// The value to check for equality.
+ /// Ignore the case from the PropertyName and PropertyValue (string only).
+ /// Throw an exception when the internal matching fails because of invalid input.
+ public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false)
+ {
+ Guard.NotNull(value, nameof(value));
- ///
- public bool IgnoreCase { get; }
+ MatchBehaviour = matchBehaviour;
+ IgnoreCase = ignoreCase;
+ ThrowException = throwException;
- ///
- public bool ThrowException { get; }
+ Value = value;
+ _valueAsJToken = ConvertValueToJToken(value);
+ _jTokenConverter = ignoreCase
+ ? (Func)Rename
+ : jToken => jToken;
+ }
- private readonly JToken _valueAsJToken;
- private readonly Func _jTokenConverter;
+ ///
+ public double IsMatch(object? input)
+ {
+ bool match = false;
- ///
- /// Initializes a new instance of the class.
- ///
- /// The string value to check for equality.
- /// Ignore the case from the PropertyName and PropertyValue (string only).
- /// Throw an exception when the internal matching fails because of invalid input.
- public JsonMatcher(string value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
+ // When input is null or byte[], return Mismatch.
+ if (input != null && input is not byte[])
{
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The object value to check for equality.
- /// Ignore the case from the PropertyName and PropertyValue (string only).
- /// Throw an exception when the internal matching fails because of invalid input.
- public JsonMatcher(object value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// The value to check for equality.
- /// Ignore the case from the PropertyName and PropertyValue (string only).
- /// Throw an exception when the internal matching fails because of invalid input.
- public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false)
- {
- Guard.NotNull(value, nameof(value));
-
- MatchBehaviour = matchBehaviour;
- IgnoreCase = ignoreCase;
- ThrowException = throwException;
-
- Value = value;
- _valueAsJToken = ConvertValueToJToken(value);
- _jTokenConverter = ignoreCase
- ? (Func)Rename
- : jToken => jToken;
- }
-
- ///
- public double IsMatch(object? input)
- {
- bool match = false;
-
- // When input is null or byte[], return Mismatch.
- if (input != null && input is not byte[])
+ try
{
- try
- {
- var inputAsJToken = ConvertValueToJToken(input);
+ var inputAsJToken = ConvertValueToJToken(input);
- match = IsMatch(
- _jTokenConverter(_valueAsJToken),
- _jTokenConverter(inputAsJToken));
- }
- catch (JsonException)
+ match = IsMatch(
+ _jTokenConverter(_valueAsJToken),
+ _jTokenConverter(inputAsJToken));
+ }
+ catch (JsonException)
+ {
+ if (ThrowException)
{
- if (ThrowException)
- {
- throw;
- }
+ throw;
}
}
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
- ///
- /// Compares the input against the matcher value
- ///
- /// Matcher value
- /// Input value
- ///
- protected virtual bool IsMatch(JToken value, JToken input)
+ return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
+ }
+
+ ///
+ /// Compares the input against the matcher value
+ ///
+ /// Matcher value
+ /// Input value
+ ///
+ protected virtual bool IsMatch(JToken value, JToken input)
+ {
+ return JToken.DeepEquals(value, input);
+ }
+
+ private static JToken ConvertValueToJToken(object value)
+ {
+ // Check if JToken, string, IEnumerable or object
+ switch (value)
{
- return JToken.DeepEquals(value, input);
- }
+ case JToken tokenValue:
+ return tokenValue;
- private static JToken ConvertValueToJToken(object value)
- {
- // Check if JToken, string, IEnumerable or object
- switch (value)
- {
- case JToken tokenValue:
- return tokenValue;
+ case string stringValue:
+ return JsonUtils.Parse(stringValue)!;
- case string stringValue:
- return JsonUtils.Parse(stringValue);
+ case IEnumerable enumerableValue:
+ return JArray.FromObject(enumerableValue);
- case IEnumerable enumerableValue:
- return JArray.FromObject(enumerableValue);
-
- default:
- return JObject.FromObject(value);
- }
- }
-
- private static string? ToUpper(string? input)
- {
- return input?.ToUpperInvariant();
- }
-
- // https://stackoverflow.com/questions/11679804/json-net-rename-properties
- private static JToken Rename(JToken json)
- {
- if (json is JProperty property)
- {
- JToken propertyValue = property.Value;
- if (propertyValue.Type == JTokenType.String)
- {
- string stringValue = propertyValue.Value();
- propertyValue = ToUpper(stringValue);
- }
-
- return new JProperty(ToUpper(property.Name), Rename(propertyValue));
- }
-
- if (json is JArray array)
- {
- var renamedValues = array.Select(Rename);
- return new JArray(renamedValues);
- }
-
- if (json is JObject obj)
- {
- var renamedProperties = obj.Properties().Select(Rename);
- return new JObject(renamedProperties);
- }
-
- return json;
+ default:
+ return JObject.FromObject(value);
}
}
+
+ private static string? ToUpper(string? input)
+ {
+ return input?.ToUpperInvariant();
+ }
+
+ // https://stackoverflow.com/questions/11679804/json-net-rename-properties
+ private static JToken Rename(JToken json)
+ {
+ if (json is JProperty property)
+ {
+ JToken propertyValue = property.Value;
+ if (propertyValue.Type == JTokenType.String)
+ {
+ string stringValue = propertyValue.Value()!;
+ propertyValue = ToUpper(stringValue);
+ }
+
+ return new JProperty(ToUpper(property.Name)!, Rename(propertyValue));
+ }
+
+ if (json is JArray array)
+ {
+ var renamedValues = array.Select(Rename);
+ return new JArray(renamedValues);
+ }
+
+ if (json is JObject obj)
+ {
+ var renamedProperties = obj.Properties().Select(Rename);
+ return new JObject(renamedProperties);
+ }
+
+ return json;
+ }
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/JsonPartialMatcher.cs b/src/WireMock.Net/Matchers/JsonPartialMatcher.cs
index 3e457393..9527e581 100644
--- a/src/WireMock.Net/Matchers/JsonPartialMatcher.cs
+++ b/src/WireMock.Net/Matchers/JsonPartialMatcher.cs
@@ -1,38 +1,35 @@
-using JetBrains.Annotations;
+namespace WireMock.Matchers;
-namespace WireMock.Matchers
+///
+/// JsonPartialMatcher
+///
+public class JsonPartialMatcher : AbstractJsonPartialMatcher
{
- ///
- /// JsonPartialMatcher
- ///
- public class JsonPartialMatcher : AbstractJsonPartialMatcher
+ ///
+ public override string Name => nameof(JsonPartialMatcher);
+
+ ///
+ public JsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false)
+ : base(value, ignoreCase, throwException)
{
- ///
- public override string Name => nameof(JsonPartialMatcher);
-
- ///
- public JsonPartialMatcher([NotNull] string value, bool ignoreCase = false, bool throwException = false)
- : base(value, ignoreCase, throwException)
- {
- }
-
- ///
- public JsonPartialMatcher([NotNull] object value, bool ignoreCase = false, bool throwException = false)
- : base(value, ignoreCase, throwException)
- {
- }
-
- ///
- public JsonPartialMatcher(MatchBehaviour matchBehaviour, [NotNull] object value, bool ignoreCase = false, bool throwException = false)
- : base(matchBehaviour, value, ignoreCase, throwException)
- {
- }
-
- ///
- protected override bool IsMatch(string value, string input)
- {
- var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, ThrowException, value);
- return MatchScores.IsPerfect(exactStringMatcher.IsMatch(input));
- }
}
-}
+
+ ///
+ public JsonPartialMatcher(object value, bool ignoreCase = false, bool throwException = false)
+ : base(value, ignoreCase, throwException)
+ {
+ }
+
+ ///
+ public JsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false)
+ : base(matchBehaviour, value, ignoreCase, throwException)
+ {
+ }
+
+ ///
+ protected override bool IsMatch(string value, string input)
+ {
+ var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, ThrowException, MatchOperator.Or, value);
+ return MatchScores.IsPerfect(exactStringMatcher.IsMatch(input));
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/JsonPartialWildCardMatcher.cs b/src/WireMock.Net/Matchers/JsonPartialWildCardMatcher.cs
index 5f804150..bc0deb04 100644
--- a/src/WireMock.Net/Matchers/JsonPartialWildCardMatcher.cs
+++ b/src/WireMock.Net/Matchers/JsonPartialWildCardMatcher.cs
@@ -1,38 +1,37 @@
using JetBrains.Annotations;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// JsonPartialWildCardMatcher
+///
+public class JsonPartialWildcardMatcher : AbstractJsonPartialMatcher
{
- ///
- /// JsonPartialWildCardMatcher
- ///
- public class JsonPartialWildcardMatcher : AbstractJsonPartialMatcher
+ ///
+ public override string Name => nameof(JsonPartialWildcardMatcher);
+
+ ///
+ public JsonPartialWildcardMatcher(string value, bool ignoreCase = false, bool throwException = false)
+ : base(value, ignoreCase, throwException)
{
- ///
- public override string Name => nameof(JsonPartialWildcardMatcher);
-
- ///
- public JsonPartialWildcardMatcher([NotNull] string value, bool ignoreCase = false, bool throwException = false)
- : base(value, ignoreCase, throwException)
- {
- }
-
- ///
- public JsonPartialWildcardMatcher([NotNull] object value, bool ignoreCase = false, bool throwException = false)
- : base(value, ignoreCase, throwException)
- {
- }
-
- ///
- public JsonPartialWildcardMatcher(MatchBehaviour matchBehaviour, [NotNull] object value, bool ignoreCase = false, bool throwException = false)
- : base(matchBehaviour, value, ignoreCase, throwException)
- {
- }
-
- ///
- protected override bool IsMatch(string value, string input)
- {
- var wildcardStringMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, value, IgnoreCase);
- return MatchScores.IsPerfect(wildcardStringMatcher.IsMatch(input));
- }
}
-}
+
+ ///
+ public JsonPartialWildcardMatcher(object value, bool ignoreCase = false, bool throwException = false)
+ : base(value, ignoreCase, throwException)
+ {
+ }
+
+ ///
+ public JsonPartialWildcardMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false)
+ : base(matchBehaviour, value, ignoreCase, throwException)
+ {
+ }
+
+ ///
+ protected override bool IsMatch(string value, string input)
+ {
+ var wildcardStringMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, value, IgnoreCase);
+ return MatchScores.IsPerfect(wildcardStringMatcher.IsMatch(input));
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/LinqMatcher.cs b/src/WireMock.Net/Matchers/LinqMatcher.cs
index 76330fab..df69ad55 100644
--- a/src/WireMock.Net/Matchers/LinqMatcher.cs
+++ b/src/WireMock.Net/Matchers/LinqMatcher.cs
@@ -1,146 +1,151 @@
using System.Linq;
using System.Linq.Dynamic.Core;
using AnyOfTypes;
-using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
+using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
-using Stef.Validation;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// System.Linq.Dynamic.Core Expression Matcher
+///
+///
+///
+public class LinqMatcher : IObjectMatcher, IStringMatcher
{
+ private readonly AnyOf[] _patterns;
+
+ ///
+ public MatchBehaviour MatchBehaviour { get; }
+ ///
+ public bool ThrowException { get; }
+
///
- /// System.Linq.Dynamic.Core Expression Matcher
+ /// Initializes a new instance of the class.
///
- ///
- ///
- public class LinqMatcher : IObjectMatcher, IStringMatcher
+ /// The pattern.
+ public LinqMatcher(AnyOf pattern) : this(new[] { pattern })
{
- private readonly AnyOf[] _patterns;
-
- ///
- public MatchBehaviour MatchBehaviour { get; }
- ///
- public bool ThrowException { get; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The pattern.
- public LinqMatcher([NotNull] AnyOf pattern) : this(new[] { pattern })
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The patterns.
- public LinqMatcher([NotNull] params AnyOf[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// The pattern.
- public LinqMatcher(MatchBehaviour matchBehaviour, [NotNull] AnyOf pattern) : this(matchBehaviour, false, pattern)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- /// The patterns.
- /// Throw an exception when the internal matching fails because of invalid input.
- public LinqMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params AnyOf[] patterns)
- {
- Guard.NotNull(patterns, nameof(patterns));
-
- MatchBehaviour = matchBehaviour;
- ThrowException = throwException;
- _patterns = patterns;
- }
-
- ///
- public double IsMatch(string input)
- {
- double match = MatchScores.Mismatch;
-
- // Convert a single input string to a Queryable string-list with 1 entry.
- IQueryable queryable = new[] { input }.AsQueryable();
-
- try
- {
- // Use the Any(...) method to check if the result matches
- match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern.GetPattern())));
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, match);
- }
- catch
- {
- if (ThrowException)
- {
- throw;
- }
- }
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, match);
- }
-
- ///
- public double IsMatch(object input)
- {
- double match = MatchScores.Mismatch;
-
- JObject value;
- switch (input)
- {
- case JObject valueAsJObject:
- value = valueAsJObject;
- break;
-
- default:
- value = JObject.FromObject(input);
- break;
- }
-
- // Convert a single object to a Queryable JObject-list with 1 entry.
- var queryable1 = new[] { value }.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.
- match = MatchScores.ToScore(_patterns.Select(pattern => queryable2.Any(pattern)));
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, match);
- }
- catch
- {
- if (ThrowException)
- {
- throw;
- }
- }
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, match);
- }
-
- ///
- public AnyOf[] GetPatterns()
- {
- return _patterns;
- }
-
- ///
- public string Name => "LinqMatcher";
}
-}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The patterns.
+ public LinqMatcher(params AnyOf[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// The pattern.
+ public LinqMatcher(MatchBehaviour matchBehaviour, AnyOf pattern) : this(matchBehaviour, false, MatchOperator.Or, pattern)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The match behaviour.
+ /// Throw an exception when the internal matching fails because of invalid input.
+ /// The to use. (default = "Or")
+ /// The patterns.
+ public LinqMatcher(
+ MatchBehaviour matchBehaviour,
+ bool throwException = false,
+ MatchOperator matchOperator = MatchOperator.Or,
+ params AnyOf[] patterns)
+ {
+ _patterns = Guard.NotNull(patterns);
+ MatchBehaviour = matchBehaviour;
+ ThrowException = throwException;
+ MatchOperator = matchOperator;
+ }
+
+ ///
+ public double IsMatch(string input)
+ {
+ double match = MatchScores.Mismatch;
+
+ // Convert a single input string to a Queryable string-list with 1 entry.
+ IQueryable queryable = new[] { input }.AsQueryable();
+
+ try
+ {
+ // Use the Any(...) method to check if the result matches
+ match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern.GetPattern())).ToArray(), MatchOperator);
+
+ return MatchBehaviourHelper.Convert(MatchBehaviour, match);
+ }
+ catch
+ {
+ if (ThrowException)
+ {
+ throw;
+ }
+ }
+
+ return MatchBehaviourHelper.Convert(MatchBehaviour, match);
+ }
+
+ ///
+ public double IsMatch(object input)
+ {
+ double match = MatchScores.Mismatch;
+
+ JObject value;
+ switch (input)
+ {
+ case JObject valueAsJObject:
+ value = valueAsJObject;
+ break;
+
+ default:
+ value = JObject.FromObject(input);
+ break;
+ }
+
+ // Convert a single object to a Queryable JObject-list with 1 entry.
+ var queryable1 = new[] { value }.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.
+ match = MatchScores.ToScore(_patterns.Select(pattern => queryable2.Any(pattern)).ToArray(), MatchOperator);
+
+ return MatchBehaviourHelper.Convert(MatchBehaviour, match);
+ }
+ catch
+ {
+ if (ThrowException)
+ {
+ throw;
+ }
+ }
+
+ return MatchBehaviourHelper.Convert(MatchBehaviour, match);
+ }
+
+ ///
+ public AnyOf[] GetPatterns()
+ {
+ return _patterns;
+ }
+
+ ///
+ public MatchOperator MatchOperator { get; }
+
+ ///
+ public string Name => "LinqMatcher";
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/MatchOperator.cs b/src/WireMock.Net/Matchers/MatchOperator.cs
new file mode 100644
index 00000000..b54adc9e
--- /dev/null
+++ b/src/WireMock.Net/Matchers/MatchOperator.cs
@@ -0,0 +1,22 @@
+namespace WireMock.Matchers;
+
+///
+/// The Operator to use when multiple patterns are defined.
+///
+public enum MatchOperator
+{
+ ///
+ /// Only one pattern needs to match. [Default]
+ ///
+ Or,
+
+ ///
+ /// All patterns should match.
+ ///
+ And,
+
+ ///
+ /// The average value from all patterns.
+ ///
+ Average,
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/MatchScores.cs b/src/WireMock.Net/Matchers/MatchScores.cs
index 5cefe4ce..cb79e712 100644
--- a/src/WireMock.Net/Matchers/MatchScores.cs
+++ b/src/WireMock.Net/Matchers/MatchScores.cs
@@ -1,75 +1,84 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// MatchScores
+///
+public static class MatchScores
{
///
- /// MatchScores
+ /// The tolerance
///
- public static class MatchScores
+ public const double Tolerance = 0.000001;
+
+ ///
+ /// The default mismatch score
+ ///
+ public const double Mismatch = 0.0;
+
+ ///
+ /// The default perfect match score
+ ///
+ public const double Perfect = 1.0;
+
+ ///
+ /// The almost perfect match score
+ ///
+ public const double AlmostPerfect = 0.99;
+
+ ///
+ /// Is the value a perfect match?
+ ///
+ /// The value.
+ /// true/false
+ public static bool IsPerfect(double value)
{
- ///
- /// The tolerance
- ///
- public const double Tolerance = 0.000001;
+ return Math.Abs(value - Perfect) < Tolerance;
+ }
- ///
- /// The default mismatch score
- ///
- public const double Mismatch = 0.0;
+ ///
+ /// Convert a bool to the score.
+ ///
+ /// if set to true [value].
+ /// score
+ public static double ToScore(bool value)
+ {
+ return value ? Perfect : Mismatch;
+ }
- ///
- /// The default perfect match score
- ///
- public const double Perfect = 1.0;
+ ///
+ /// Calculates the score from multiple values.
+ ///
+ /// The values.
+ /// The .
+ /// average score
+ public static double ToScore(IReadOnlyCollection values, MatchOperator matchOperator)
+ {
+ return ToScore(values.Select(ToScore).ToArray(), matchOperator);
+ }
- ///
- /// The almost perfect match score
- ///
- public const double AlmostPerfect = 0.99;
-
- ///
- /// Is the value a perfect match?
- ///
- /// The value.
- /// true/false
- public static bool IsPerfect(double value)
+ ///
+ /// Calculates the score from multiple values.
+ ///
+ /// The values.
+ ///
+ /// average score
+ public static double ToScore(IReadOnlyCollection values, MatchOperator matchOperator)
+ {
+ if (!values.Any())
{
- return Math.Abs(value - Perfect) < Tolerance;
+ return Mismatch;
}
- ///
- /// Convert a bool to the score.
- ///
- /// if set to true [value].
- /// score
- public static double ToScore(bool value)
+ return matchOperator switch
{
- return value ? Perfect : Mismatch;
- }
-
- ///
- /// Calculates the score from multiple values.
- ///
- /// The values.
- /// average score
- [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
- public static double ToScore(IEnumerable values)
- {
- return values.Any() ? values.Select(ToScore).Average() : Mismatch;
- }
-
- ///
- /// Calculates the score from multiple values.
- ///
- /// The values.
- /// average score
- [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
- public static double ToScore(IEnumerable values)
- {
- return values.Any() ? values.Average() : Mismatch;
- }
+ MatchOperator.Or => ToScore(values.Any(IsPerfect)),
+ MatchOperator.And => ToScore(values.All(IsPerfect)),
+ _ => values.Average()
+ };
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/NotNullOrEmptyMatcher.cs b/src/WireMock.Net/Matchers/NotNullOrEmptyMatcher.cs
index 4b16b48e..a971f3e2 100644
--- a/src/WireMock.Net/Matchers/NotNullOrEmptyMatcher.cs
+++ b/src/WireMock.Net/Matchers/NotNullOrEmptyMatcher.cs
@@ -2,67 +2,69 @@ using System.Linq;
using AnyOfTypes;
using WireMock.Models;
-namespace WireMock.Matchers
+namespace WireMock.Matchers;
+
+///
+/// NotNullOrEmptyMatcher
+///
+///
+public class NotNullOrEmptyMatcher : IObjectMatcher, IStringMatcher
{
+ ///
+ public string Name => "NotNullOrEmptyMatcher";
+
+ ///
+ public MatchBehaviour MatchBehaviour { get; }
+
+ ///
+ public bool ThrowException { get; }
+
///
- /// NotNullOrEmptyMatcher
+ /// Initializes a new instance of the class.
///
- ///
- public class NotNullOrEmptyMatcher : IObjectMatcher, IStringMatcher
+ /// The match behaviour.
+ public NotNullOrEmptyMatcher(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
- ///
- public string Name => "NotNullOrEmptyMatcher";
-
- ///
- public MatchBehaviour MatchBehaviour { get; }
-
- ///
- public bool ThrowException { get; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The match behaviour.
- public NotNullOrEmptyMatcher(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
- {
- MatchBehaviour = matchBehaviour;
- }
-
- ///
- public double IsMatch(object input)
- {
- bool match;
-
- switch (input)
- {
- case string @string:
- match = !string.IsNullOrEmpty(@string);
- break;
-
- case byte[] bytes:
- match = bytes != null && bytes.Any();
- break;
-
- default:
- match = input != null;
- break;
- }
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
- }
-
- ///
- public double IsMatch(string input)
- {
- var match = !string.IsNullOrEmpty(input);
-
- return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
- }
-
- ///
- public AnyOf[] GetPatterns()
- {
- return new AnyOf[0];
- }
+ MatchBehaviour = matchBehaviour;
}
+
+ ///
+ public double IsMatch(object? input)
+ {
+ bool match;
+
+ switch (input)
+ {
+ case string @string:
+ match = !string.IsNullOrEmpty(@string);
+ break;
+
+ case byte[] bytes:
+ match = bytes.Any();
+ break;
+
+ default:
+ match = input != null;
+ break;
+ }
+
+ return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
+ }
+
+ ///
+ public double IsMatch(string? input)
+ {
+ var match = !string.IsNullOrEmpty(input);
+
+ return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
+ }
+
+ ///
+ public AnyOf[] GetPatterns()
+ {
+ return new AnyOf[0];
+ }
+
+ ///
+ public MatchOperator MatchOperator { get; } = MatchOperator.Or;
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/RegexMatcher.cs b/src/WireMock.Net/Matchers/RegexMatcher.cs
index 03a77551..fb20eeae 100644
--- a/src/WireMock.Net/Matchers/RegexMatcher.cs
+++ b/src/WireMock.Net/Matchers/RegexMatcher.cs
@@ -33,8 +33,14 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
/// Ignore the case from the pattern.
/// Throw an exception when the internal matching fails because of invalid input.
/// Use RegexExtended (default = true).
- public RegexMatcher([NotNull, RegexPattern] AnyOf pattern, bool ignoreCase = false, bool throwException = false, bool useRegexExtended = true) :
- this(MatchBehaviour.AcceptOnMatch, new[] { pattern }, ignoreCase, throwException, useRegexExtended)
+ /// The to use. (default = "Or")
+ public RegexMatcher(
+ [RegexPattern] AnyOf pattern,
+ bool ignoreCase = false,
+ bool throwException = false,
+ bool useRegexExtended = true,
+ MatchOperator matchOperator = MatchOperator.Or) :
+ this(MatchBehaviour.AcceptOnMatch, new[] { pattern }, ignoreCase, throwException, useRegexExtended, matchOperator)
{
}
@@ -46,8 +52,15 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
/// Ignore the case from the pattern.
/// Throw an exception when the internal matching fails because of invalid input.
/// Use RegexExtended (default = true).
- public RegexMatcher(MatchBehaviour matchBehaviour, [NotNull, RegexPattern] AnyOf pattern, bool ignoreCase = false, bool throwException = false, bool useRegexExtended = true) :
- this(matchBehaviour, new[] { pattern }, ignoreCase, throwException, useRegexExtended)
+ /// The to use. (default = "Or")
+ public RegexMatcher(
+ MatchBehaviour matchBehaviour,
+ [RegexPattern] AnyOf pattern,
+ bool ignoreCase = false,
+ bool throwException = false,
+ bool useRegexExtended = true,
+ MatchOperator matchOperator = MatchOperator.Or) :
+ this(matchBehaviour, new[] { pattern }, ignoreCase, throwException, useRegexExtended, matchOperator)
{
}
@@ -59,14 +72,20 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
/// Ignore the case from the pattern.
/// Throw an exception when the internal matching fails because of invalid input.
/// Use RegexExtended (default = true).
- public RegexMatcher(MatchBehaviour matchBehaviour, [NotNull, RegexPattern] AnyOf[] patterns, bool ignoreCase = false, bool throwException = false, bool useRegexExtended = true)
+ /// The to use. (default = "Or")
+ public RegexMatcher(
+ MatchBehaviour matchBehaviour,
+ [RegexPattern] AnyOf[] patterns,
+ bool ignoreCase = false,
+ bool throwException = false,
+ bool useRegexExtended = true,
+ MatchOperator matchOperator = MatchOperator.Or)
{
- Guard.NotNull(patterns, nameof(patterns));
-
- _patterns = patterns;
+ _patterns = Guard.NotNull(patterns);
IgnoreCase = ignoreCase;
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
+ MatchOperator = matchOperator;
RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline;
@@ -79,14 +98,14 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
}
///
- public virtual double IsMatch(string input)
+ public virtual double IsMatch(string? input)
{
double match = MatchScores.Mismatch;
if (input != null)
{
try
{
- match = MatchScores.ToScore(_expressions.Select(e => e.IsMatch(input)));
+ match = MatchScores.ToScore(_expressions.Select(e => e.IsMatch(input)).ToArray(), MatchOperator);
}
catch (Exception)
{
@@ -111,4 +130,8 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
///
public bool IgnoreCase { get; }
+
+ ///
+ public MatchOperator MatchOperator { get; }
+
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
index a6fd558d..e55e820a 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
@@ -1,211 +1,226 @@
-using JetBrains.Annotations;
using System;
using System.Linq;
+using AnyOfTypes;
+using Stef.Validation;
+using WireMock.Models;
using WireMock.Types;
using WireMock.Util;
-using Stef.Validation;
-namespace WireMock.Matchers.Request
+namespace WireMock.Matchers.Request;
+
+///
+/// The request body matcher.
+///
+public class RequestMessageBodyMatcher : IRequestMatcher
{
///
- /// The request body matcher.
+ /// The body function
///
- public class RequestMessageBodyMatcher : IRequestMatcher
+ public Func? Func { get; }
+
+ ///
+ /// The body data function for byte[]
+ ///
+ public Func? DataFunc { get; }
+
+ ///
+ /// The body data function for json
+ ///
+ public Func