Write logging in case a Matcher throws an exception (#986)

* ThrowException

* ...

* .

* ...

* b

* fix test

* ...

* .

* sonar

* ft

* .

* fix tst
This commit is contained in:
Stef Heyenrath
2023-08-21 20:07:46 +02:00
committed by GitHub
parent 09a302baf2
commit 93c87845c2
88 changed files with 1266 additions and 1244 deletions
@@ -1,21 +1,25 @@
using System; using System;
namespace WireMock.Admin.Mappings namespace WireMock.Admin.Mappings;
/// <summary>
/// Status
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class StatusModel
{ {
/// <summary> /// <summary>
/// Status /// The optional guid.
/// </summary> /// </summary>
[FluentBuilder.AutoGenerateBuilder] public Guid? Guid { get; set; }
public class StatusModel
{
/// <summary>
/// The optional guid.
/// </summary>
public Guid? Guid { get; set; }
/// <summary> /// <summary>
/// The status (can also contain the error message). /// The status.
/// </summary> /// </summary>
public string Status { get; set; } public string? Status { get; set; }
}
/// <summary>
/// The error message.
/// </summary>
public string? Error { get; set; }
} }
@@ -62,11 +62,6 @@ public class SettingsModel
/// </summary> /// </summary>
public bool? HandleRequestsSynchronously { get; set; } public bool? HandleRequestsSynchronously { get; set; }
/// <summary>
/// Throw an exception when the Matcher fails because of invalid input. (default set to <c>false</c>).
/// </summary>
public bool? ThrowExceptionWhenMatcherFails { get; set; }
/// <summary> /// <summary>
/// Use the RegexExtended instead of the default <see cref="Regex"/>. (default set to <c>true</c>). /// Use the RegexExtended instead of the default <see cref="Regex"/>. (default set to <c>true</c>).
/// </summary> /// </summary>
@@ -1,121 +1,120 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using System.Collections.Generic; using System.Collections.Generic;
namespace WireMock.Handlers namespace WireMock.Handlers;
/// <summary>
/// Handler to interact with the file system to handle folders and read and write (static mapping) files.
/// </summary>
public interface IFileSystemHandler
{ {
/// <summary> /// <summary>
/// Handler to interact with the file system to handle folders and read and write (static mapping) files. /// Gets the folder where the static mappings are located. For local file system, this would be `{CurrentFolder}/__admin/mappings`.
/// </summary> /// </summary>
public interface IFileSystemHandler /// <returns>The folder name.</returns>
{ string GetMappingFolder();
/// <summary>
/// Gets the folder where the static mappings are located. For local file system, this would be `{CurrentFolder}/__admin/mappings`.
/// </summary>
/// <returns>The folder name.</returns>
string GetMappingFolder();
/// <summary> /// <summary>
/// Determines whether the given path refers to an existing directory on disk. /// Determines whether the given path refers to an existing directory on disk.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <returns>true if path refers to an existing directory; false if the directory does not exist or an error occurs when trying to determine if the specified directory exists.</returns> /// <returns>true if path refers to an existing directory; false if the directory does not exist or an error occurs when trying to determine if the specified directory exists.</returns>
bool FolderExists([NotNull] string path); bool FolderExists([NotNull] string path);
/// <summary> /// <summary>
/// Creates all directories and subdirectories in the specified path unless they already exist. /// Creates all directories and subdirectories in the specified path unless they already exist.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
void CreateFolder([NotNull] string path); void CreateFolder([NotNull] string path);
/// <summary> /// <summary>
/// Returns an enumerable collection of file names in a specified path. /// Returns an enumerable collection of file names in a specified path.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <param name="includeSubdirectories">A value indicating whether subdirectories should also included when enumerating files.</param> /// <param name="includeSubdirectories">A value indicating whether subdirectories should also included when enumerating files.</param>
/// <returns>An enumerable collection of the full names (including paths) for the files in the directory (and optionally subdirectories) specified by path.</returns> /// <returns>An enumerable collection of the full names (including paths) for the files in the directory (and optionally subdirectories) specified by path.</returns>
IEnumerable<string> EnumerateFiles([NotNull] string path, bool includeSubdirectories); IEnumerable<string> EnumerateFiles([NotNull] string path, bool includeSubdirectories);
/// <summary> /// <summary>
/// Read a static mapping file as text. /// Read a static mapping file as text.
/// </summary> /// </summary>
/// <param name="path">The path (folder + filename with .json extension).</param> /// <param name="path">The path (folder + filename with .json extension).</param>
/// <returns>The file content as text.</returns> /// <returns>The file content as text.</returns>
string ReadMappingFile([NotNull] string path); string ReadMappingFile([NotNull] string path);
/// <summary> /// <summary>
/// Write the static mapping file. /// Write the static mapping file.
/// </summary> /// </summary>
/// <param name="path">The path (folder + filename with .json extension).</param> /// <param name="path">The path (folder + filename with .json extension).</param>
/// <param name="text">The text.</param> /// <param name="text">The text.</param>
void WriteMappingFile([NotNull] string path, [NotNull] string text); void WriteMappingFile([NotNull] string path, [NotNull] string text);
/// <summary> /// <summary>
/// Read a response body file as byte[]. /// Read a response body file as byte[].
/// </summary> /// </summary>
/// <param name="path">The path or filename from the file to read.</param> /// <param name="path">The path or filename from the file to read.</param>
/// <returns>The file content as bytes.</returns> /// <returns>The file content as bytes.</returns>
byte[] ReadResponseBodyAsFile([NotNull] string path); byte[] ReadResponseBodyAsFile([NotNull] string path);
/// <summary> /// <summary>
/// Read a response body file as text. /// Read a response body file as text.
/// </summary> /// </summary>
/// <param name="path">The path or filename from the file to read.</param> /// <param name="path">The path or filename from the file to read.</param>
/// <returns>The file content as text.</returns> /// <returns>The file content as text.</returns>
string ReadResponseBodyAsString([NotNull] string path); string ReadResponseBodyAsString([NotNull] string path);
/// <summary> /// <summary>
/// Delete a file. /// Delete a file.
/// </summary> /// </summary>
/// <param name="filename">The filename.</param> /// <param name="filename">The filename.</param>
void DeleteFile([NotNull] string filename); void DeleteFile([NotNull] string filename);
/// <summary> /// <summary>
/// Determines whether the given path refers to an existing file on disk. /// Determines whether the given path refers to an existing file on disk.
/// </summary> /// </summary>
/// <param name="filename">The filename.</param> /// <param name="filename">The filename.</param>
/// <returns>true if path refers to an existing file; false if the file does not exist.</returns> /// <returns>true if path refers to an existing file; false if the file does not exist.</returns>
bool FileExists([NotNull] string filename); bool FileExists([NotNull] string filename);
/// <summary> /// <summary>
/// Write a file. /// Write a file.
/// </summary> /// </summary>
/// <param name="filename">The filename.</param> /// <param name="filename">The filename.</param>
/// <param name="bytes">The bytes.</param> /// <param name="bytes">The bytes.</param>
void WriteFile([NotNull] string filename, [NotNull] byte[] bytes); void WriteFile([NotNull] string filename, [NotNull] byte[] bytes);
/// <summary> /// <summary>
/// Write a file. /// Write a file.
/// </summary> /// </summary>
/// <param name="folder">The folder.</param> /// <param name="folder">The folder.</param>
/// <param name="filename">The filename.</param> /// <param name="filename">The filename.</param>
/// <param name="bytes">The bytes.</param> /// <param name="bytes">The bytes.</param>
void WriteFile([NotNull] string folder, [NotNull] string filename, [NotNull] byte[] bytes); void WriteFile([NotNull] string folder, [NotNull] string filename, [NotNull] byte[] bytes);
/// <summary> /// <summary>
/// Read a file as bytes. /// Read a file as bytes.
/// </summary> /// </summary>
/// <param name="filename">The filename.</param> /// <param name="filename">The filename.</param>
/// <returns>The file content as bytes.</returns> /// <returns>The file content as bytes.</returns>
byte[] ReadFile([NotNull] string filename); byte[] ReadFile([NotNull] string filename);
/// <summary> /// <summary>
/// Read a file as string. /// Read a file as string.
/// </summary> /// </summary>
/// <param name="filename">The filename.</param> /// <param name="filename">The filename.</param>
/// <returns>The file content as a string.</returns> /// <returns>The file content as a string.</returns>
string ReadFileAsString([NotNull] string filename); string ReadFileAsString([NotNull] string filename);
/// <summary> /// <summary>
/// Gets the folder where the unmatched requests should be stored. For local file system, this would be `{CurrentFolder}/requests/unmatched`. /// Gets the folder where the unmatched requests should be stored. For local file system, this would be `{CurrentFolder}/requests/unmatched`.
/// </summary> /// </summary>
/// <returns>The folder name.</returns> /// <returns>The folder name.</returns>
string GetUnmatchedRequestsFolder(); string GetUnmatchedRequestsFolder();
/// <summary> /// <summary>
/// Write a unmatched request to the Unmatched RequestsFolder. /// Write a unmatched request to the Unmatched RequestsFolder.
/// </summary> /// </summary>
/// <param name="filename">The filename.</param> /// <param name="filename">The filename.</param>
/// <param name="text">The text.</param> /// <param name="text">The text.</param>
void WriteUnmatchedRequest([NotNull] string filename, [NotNull] string text); void WriteUnmatchedRequest([NotNull] string filename, [NotNull] string text);
}
} }
@@ -2,65 +2,63 @@ using System;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Admin.Requests; using WireMock.Admin.Requests;
namespace WireMock.Logging namespace WireMock.Logging;
/// <summary>
/// IWireMockLogger interface
/// </summary>
[PublicAPI]
public interface IWireMockLogger
{ {
/// <summary> /// <summary>
/// IWireMockLogger interface /// Writes the message at the Debug level using the specified parameters.
/// </summary> /// </summary>
/// <param name="formatString">The format string.</param>
/// <param name="args">The arguments.</param>
[PublicAPI] [PublicAPI]
public interface IWireMockLogger [StringFormatMethod("formatString")]
{ void Debug(string formatString, params object[] args);
/// <summary>
/// Writes the message at the Debug level using the specified parameters.
/// </summary>
/// <param name="formatString">The format string.</param>
/// <param name="args">The arguments.</param>
[PublicAPI]
[StringFormatMethod("formatString")]
void Debug(string formatString, params object[] args);
/// <summary> /// <summary>
/// Writes the message at the Info level using the specified parameters. /// Writes the message at the Info level using the specified parameters.
/// </summary> /// </summary>
/// <param name="formatString">The format string.</param> /// <param name="formatString">The format string.</param>
/// <param name="args">The arguments.</param> /// <param name="args">The arguments.</param>
[PublicAPI] [PublicAPI]
[StringFormatMethod("formatString")] [StringFormatMethod("formatString")]
void Info(string formatString, params object[] args); void Info(string formatString, params object[] args);
/// <summary> /// <summary>
/// Writes the message at the Warning level using the specified parameters. /// Writes the message at the Warning level using the specified parameters.
/// </summary> /// </summary>
/// <param name="formatString">The format string.</param> /// <param name="formatString">The format string.</param>
/// <param name="args">The arguments.</param> /// <param name="args">The arguments.</param>
[PublicAPI] [PublicAPI]
[StringFormatMethod("formatString")] [StringFormatMethod("formatString")]
void Warn(string formatString, params object[] args); void Warn(string formatString, params object[] args);
/// <summary> /// <summary>
/// Writes the message at the Error level using the specified parameters. /// Writes the message at the Error level using the specified parameters.
/// </summary> /// </summary>
/// <param name="formatString">The format string.</param> /// <param name="formatString">The format string.</param>
/// <param name="args">The arguments.</param> /// <param name="args">The arguments.</param>
[PublicAPI] [PublicAPI]
[StringFormatMethod("formatString")] [StringFormatMethod("formatString")]
void Error(string formatString, params object[] args); void Error(string formatString, params object[] args);
/// <summary> /// <summary>
/// Writes the message at the Error level using the specified exception. /// Writes the message at the Error level using the specified exception.
/// </summary> /// </summary>
/// <param name="formatString">The format string.</param> /// <param name="formatString">The format string.</param>
/// <param name="exception">The exception.</param> /// <param name="exception">The exception.</param>
[PublicAPI] [PublicAPI]
[StringFormatMethod("formatString")] void Error(string formatString, Exception exception);
void Error(string formatString, Exception exception);
/// <summary> /// <summary>
/// Writes the LogEntryModel (LogRequestModel, LogResponseModel and more). /// Writes the LogEntryModel (LogRequestModel, LogResponseModel and more).
/// </summary> /// </summary>
/// <param name="logEntryModel">The Request Log Model.</param> /// <param name="logEntryModel">The Request Log Model.</param>
/// <param name="isAdminRequest">Defines if this request is an admin request.</param> /// <param name="isAdminRequest">Defines if this request is an admin request.</param>
[PublicAPI] [PublicAPI]
void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest); void DebugRequestResponse(LogEntryModel logEntryModel, bool isAdminRequest);
}
} }
@@ -1,56 +1,56 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace WireMock.Matchers.Request namespace WireMock.Matchers.Request;
/// <summary>
/// IRequestMatchResult
/// </summary>
public interface IRequestMatchResult : IComparable
{ {
/// <summary> /// <summary>
/// IRequestMatchResult /// Gets the match percentage.
/// </summary> /// </summary>
public interface IRequestMatchResult : IComparable /// <value>
{ /// The match percentage.
/// <summary> /// </value>
/// Gets the match percentage. double AverageTotalScore { get; }
/// </summary>
/// <value>
/// The match percentage.
/// </value>
double AverageTotalScore { get; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether this instance is perfect match. /// Gets or sets a value indicating whether this instance is perfect match.
/// </summary> /// </summary>
/// <value> /// <value>
/// <c>true</c> if this instance is perfect match; otherwise, <c>false</c>. /// <c>true</c> if this instance is perfect match; otherwise, <c>false</c>.
/// </value> /// </value>
bool IsPerfectMatch { get; } bool IsPerfectMatch { get; }
/// <summary> /// <summary>
/// Gets the match details. /// Gets the match details.
/// </summary> /// </summary>
IList<MatchDetail> MatchDetails { get; } IList<MatchDetail> MatchDetails { get; }
/// <summary> /// <summary>
/// Gets or sets the total number of matches. /// Gets or sets the total number of matches.
/// </summary> /// </summary>
/// <value> /// <value>
/// The total number of matches. /// The total number of matches.
/// </value> /// </value>
int TotalNumber { get; } int TotalNumber { get; }
/// <summary> /// <summary>
/// Gets or sets the match-score. /// Gets or sets the match-score.
/// </summary> /// </summary>
/// <value> /// <value>
/// The match-score. /// The match-score.
/// </value> /// </value>
double TotalScore { get; } double TotalScore { get; }
/// <summary> /// <summary>
/// Adds the score. /// Adds the score.
/// </summary> /// </summary>
/// <param name="matcherType">The matcher Type.</param> /// <param name="matcherType">The matcher Type.</param>
/// <param name="score">The score.</param> /// <param name="score">The score.</param>
/// <returns>The score.</returns> /// <param name="exception">The exception [Optional].</param>
double AddScore(Type matcherType, double score); /// <returns>The score.</returns>
} double AddScore(Type matcherType, double score, Exception? exception);
} }
@@ -1,20 +1,25 @@
using System; using System;
namespace WireMock.Matchers.Request namespace WireMock.Matchers.Request;
/// <summary>
/// MatchDetail
/// </summary>
public class MatchDetail
{ {
/// <summary> /// <summary>
/// MatchDetail /// Gets or sets the type of the matcher.
/// </summary> /// </summary>
public class MatchDetail public Type MatcherType { get; set; } = null!;
{
/// <summary>
/// Gets or sets the type of the matcher.
/// </summary>
public Type MatcherType { get; set; }
/// <summary> /// <summary>
/// Gets or sets the score between 0.0 and 1.0 /// Gets or sets the score between 0.0 and 1.0
/// </summary> /// </summary>
public double Score { get; set; } public double Score { get; set; }
}
/// <summary>
/// The exception in case the Matcher throws exception.
/// [Optional]
/// </summary>
public Exception? Exception { get; set; }
} }
@@ -30,11 +30,9 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
"Newtonsoft.Json.Linq" "Newtonsoft.Json.Linq"
}; };
/// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
private readonly AnyOf<string, StringPattern>[] _patterns; private readonly AnyOf<string, StringPattern>[] _patterns;
/// <summary> /// <summary>
@@ -55,37 +53,44 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
{ {
_patterns = Guard.NotNull(patterns); _patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = false;
MatchOperator = matchOperator; MatchOperator = matchOperator;
} }
public double IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
return IsMatchInternal(input); return IsMatchInternal(input);
} }
public double IsMatch(object? input) public MatchResult IsMatch(object? input)
{ {
return IsMatchInternal(input); return IsMatchInternal(input);
} }
public double IsMatchInternal(object? input) public MatchResult IsMatchInternal(object? input)
{ {
double match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? exception = null;
if (input != null) if (input != null)
{ {
match = MatchScores.ToScore(_patterns.Select(pattern => IsMatch(input, pattern.GetPattern())).ToArray(), MatchOperator); try
{
score = MatchScores.ToScore(_patterns.Select(pattern => IsMatch(input, pattern.GetPattern())).ToArray(), MatchOperator);
}
catch (Exception ex)
{
exception = ex;
}
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
} }
private bool IsMatch(dynamic input, string pattern) private bool IsMatch(dynamic input, string pattern)
{ {
bool isMatchWithString = input is string; var isMatchWithString = input is string;
var inputValue = isMatchWithString ? input : JObject.FromObject(input); var inputValue = isMatchWithString ? input : JObject.FromObject(input);
string source = GetSourceForIsMatchWithString(pattern, isMatchWithString); var source = GetSourceForIsMatchWithString(pattern, isMatchWithString);
object? result; object? result;
@@ -155,7 +160,7 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
} }
#elif (NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP3_1 || NET5_0 || NET6_0 || NET7_0) #elif (NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP3_1 || NET5_0 || NET6_0 || NET7_0)
Assembly assembly; Assembly assembly;
try try
{ {
assembly = CSScriptLib.CSScript.Evaluator.CompileCode(source); assembly = CSScriptLib.CSScript.Evaluator.CompileCode(source);
@@ -198,10 +203,10 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
private string GetSourceForIsMatchWithString(string pattern, bool isMatchWithString) private string GetSourceForIsMatchWithString(string pattern, bool isMatchWithString)
{ {
string template = isMatchWithString ? TemplateForIsMatchWithString : TemplateForIsMatchWithDynamic; var template = isMatchWithString ? TemplateForIsMatchWithString : TemplateForIsMatchWithDynamic;
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
foreach (string @using in _usings) foreach (var @using in _usings)
{ {
stringBuilder.AppendLine($"using {@using};"); stringBuilder.AppendLine($"using {@using};");
} }
@@ -211,7 +216,7 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
return stringBuilder.ToString(); return stringBuilder.ToString();
} }
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> /// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns() public AnyOf<string, StringPattern>[] GetPatterns()
{ {
return _patterns; return _patterns;
@@ -220,6 +225,6 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
/// <inheritdoc /> /// <inheritdoc />
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc />
public string Name => "CSharpCodeMatcher"; public string Name => nameof(CSharpCodeMatcher);
} }
@@ -34,8 +34,6 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
public MatchBehaviour MatchBehaviour => MatchBehaviour.AcceptOnMatch; public MatchBehaviour MatchBehaviour => MatchBehaviour.AcceptOnMatch;
public bool ThrowException => false;
public AnyOf<string, StringPattern>[] GetPatterns() public AnyOf<string, StringPattern>[] GetPatterns()
{ {
return EmptyArray<AnyOf<string, StringPattern>>.Value; return EmptyArray<AnyOf<string, StringPattern>>.Value;
@@ -43,7 +41,7 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
public MatchOperator MatchOperator { get; } = MatchOperator.Or; public MatchOperator MatchOperator { get; } = MatchOperator.Or;
public double IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
if (string.IsNullOrEmpty(input)) if (string.IsNullOrEmpty(input))
{ {
@@ -70,9 +68,9 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
return MatchScores.Perfect; return MatchScores.Perfect;
} }
catch catch (Exception ex)
{ {
return MatchScores.Mismatch; return new MatchResult(MatchScores.Mismatch, ex);
} }
} }
} }
@@ -8,4 +8,6 @@ internal static class WireMockConstants
public const string ContentTypeJson = "application/json"; public const string ContentTypeJson = "application/json";
public const string ContentTypeTextPlain = "text/plain"; public const string ContentTypeTextPlain = "text/plain";
public const string NoMatchingFound = "No matching mapping found";
} }
@@ -0,0 +1,16 @@
using System;
namespace WireMock.Extensions;
internal static class ExceptionExtensions
{
public static Exception? ToException(this Exception[] exceptions)
{
return exceptions.Length switch
{
1 => exceptions[0],
> 1 => new AggregateException(exceptions),
_ => null
};
}
}
@@ -82,7 +82,7 @@ public class LocalFileSystemHandler : IFileSystemHandler
public virtual byte[] ReadResponseBodyAsFile(string path) public virtual byte[] ReadResponseBodyAsFile(string path)
{ {
Guard.NotNullOrEmpty(path); Guard.NotNullOrEmpty(path);
path = PathUtils.CleanPath(path); path = PathUtils.CleanPath(path)!;
// If the file exists at the given path relative to the MappingsFolder, then return that. // If the file exists at the given path relative to the MappingsFolder, then return that.
// Else the path will just be as-is. // Else the path will just be as-is.
return File.ReadAllBytes(File.Exists(PathUtils.Combine(GetMappingFolder(), path)) ? PathUtils.Combine(GetMappingFolder(), path) : path); return File.ReadAllBytes(File.Exists(PathUtils.Combine(GetMappingFolder(), path)) ? PathUtils.Combine(GetMappingFolder(), path) : path);
@@ -92,7 +92,7 @@ public class LocalFileSystemHandler : IFileSystemHandler
public virtual string ReadResponseBodyAsString(string path) public virtual string ReadResponseBodyAsString(string path)
{ {
Guard.NotNullOrEmpty(path); Guard.NotNullOrEmpty(path);
path = PathUtils.CleanPath(path); path = PathUtils.CleanPath(path)!;
// In case the path is a filename, the path will be adjusted to the MappingFolder. // In case the path is a filename, the path will be adjusted to the MappingFolder.
// Else the path will just be as-is. // Else the path will just be as-is.
return File.ReadAllText(File.Exists(PathUtils.Combine(GetMappingFolder(), path)) ? PathUtils.Combine(GetMappingFolder(), path) : path); return File.ReadAllText(File.Exists(PathUtils.Combine(GetMappingFolder(), path)) ? PathUtils.Combine(GetMappingFolder(), path) : path);
+2 -2
View File
@@ -139,13 +139,13 @@ public class Mapping : IMapping
Probability = probability; Probability = probability;
} }
/// <inheritdoc cref="IMapping.ProvideResponseAsync" /> /// <inheritdoc />
public Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage) public Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage)
{ {
return Provider.ProvideResponseAsync(this, requestMessage, Settings); return Provider.ProvideResponseAsync(this, requestMessage, Settings);
} }
/// <inheritdoc cref="IMapping.GetRequestMatchResult" /> /// <inheritdoc />
public IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string? nextState) public IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string? nextState)
{ {
var result = new RequestMatchResult(); var result = new RequestMatchResult();
@@ -20,10 +20,8 @@ public abstract class AbstractJsonPartialMatcher : JsonMatcher
/// </summary> /// </summary>
/// <param name="value">The string value to check for equality.</param> /// <param name="value">The string value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param> /// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="regex">Support Regex.</param> /// <param name="regex">Support Regex.</param>
protected AbstractJsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false, bool regex = false) protected AbstractJsonPartialMatcher(string value, bool ignoreCase = false, bool regex = false) : base(value, ignoreCase)
: base(value, ignoreCase, throwException)
{ {
Regex = regex; Regex = regex;
} }
@@ -33,10 +31,8 @@ public abstract class AbstractJsonPartialMatcher : JsonMatcher
/// </summary> /// </summary>
/// <param name="value">The object value to check for equality.</param> /// <param name="value">The object value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param> /// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="regex">Support Regex.</param> /// <param name="regex">Support Regex.</param>
protected AbstractJsonPartialMatcher(object value, bool ignoreCase = false, bool throwException = false, bool regex = false) protected AbstractJsonPartialMatcher(object value, bool ignoreCase = false, bool regex = false) : base(value, ignoreCase)
: base(value, ignoreCase, throwException)
{ {
Regex = regex; Regex = regex;
} }
@@ -47,10 +43,8 @@ public abstract class AbstractJsonPartialMatcher : JsonMatcher
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value to check for equality.</param> /// <param name="value">The value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param> /// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="regex">Support Regex.</param> /// <param name="regex">Support Regex.</param>
protected AbstractJsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false, bool regex = false) protected AbstractJsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false) : base(matchBehaviour, value, ignoreCase)
: base(matchBehaviour, value, ignoreCase, throwException)
{ {
Regex = regex; Regex = regex;
} }
@@ -75,10 +69,10 @@ public abstract class AbstractJsonPartialMatcher : JsonMatcher
} }
if (input != null && if (input != null &&
((value.Type == JTokenType.Guid && input.Type == JTokenType.String) || ((value.Type == JTokenType.Guid && input.Type == JTokenType.String) ||
(value.Type == JTokenType.String && input.Type == JTokenType.Guid))) (value.Type == JTokenType.String && input.Type == JTokenType.Guid)))
{ {
return IsMatch(value.ToString(), input.ToString()); return IsMatch(value.ToString(), input.ToString());
} }
if (input == null || value.Type != input.Type) if (input == null || value.Type != input.Type)
@@ -46,15 +46,13 @@ public class ContentTypeMatcher : WildcardMatcher
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param> /// <param name="ignoreCase">IgnoreCase (default false)</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param> public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : base(matchBehaviour, patterns, ignoreCase)
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false, bool throwException = false) :
base(matchBehaviour, patterns, ignoreCase, throwException)
{ {
_patterns = patterns; _patterns = patterns;
} }
/// <inheritdoc cref="RegexMatcher.IsMatch"/> /// <inheritdoc />
public override double IsMatch(string? input) public override MatchResult IsMatch(string? input)
{ {
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out var contentType)) if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out var contentType))
{ {
@@ -64,12 +62,12 @@ public class ContentTypeMatcher : WildcardMatcher
return base.IsMatch(contentType.MediaType); return base.IsMatch(contentType.MediaType);
} }
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> /// <inheritdoc />
public override AnyOf<string, StringPattern>[] GetPatterns() public override AnyOf<string, StringPattern>[] GetPatterns()
{ {
return _patterns; return _patterns;
} }
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc />
public override string Name => "ContentTypeMatcher"; public override string Name => nameof(ContentTypeMatcher);
} }
+9 -15
View File
@@ -14,17 +14,14 @@ public class ExactMatcher : IStringMatcher, IIgnoreCaseMatcher
{ {
private readonly AnyOf<string, StringPattern>[] _values; private readonly AnyOf<string, StringPattern>[] _values;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class. /// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary> /// </summary>
/// <param name="values">The values.</param> /// <param name="values">The values.</param>
public ExactMatcher(params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, false, false, MatchOperator.Or, values) public ExactMatcher(params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, values)
{ {
} }
@@ -33,7 +30,7 @@ public class ExactMatcher : IStringMatcher, IIgnoreCaseMatcher
/// </summary> /// </summary>
/// <param name="ignoreCase">Ignore the case from the pattern(s).</param> /// <param name="ignoreCase">Ignore the case from the pattern(s).</param>
/// <param name="values">The values.</param> /// <param name="values">The values.</param>
public ExactMatcher(bool ignoreCase, params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, ignoreCase, false, MatchOperator.Or, values) public ExactMatcher(bool ignoreCase, params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, ignoreCase, MatchOperator.Or, values)
{ {
} }
@@ -42,36 +39,33 @@ public class ExactMatcher : IStringMatcher, IIgnoreCaseMatcher
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="ignoreCase">Ignore the case from the pattern(s).</param> /// <param name="ignoreCase">Ignore the case from the pattern(s).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="values">The values.</param> /// <param name="values">The values.</param>
public ExactMatcher( public ExactMatcher(
MatchBehaviour matchBehaviour, MatchBehaviour matchBehaviour,
bool ignoreCase = false, bool ignoreCase = false,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or, MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] values) params AnyOf<string, StringPattern>[] values)
{ {
_values = Guard.NotNull(values); _values = Guard.NotNull(values);
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
IgnoreCase = ignoreCase; IgnoreCase = ignoreCase;
MatchOperator = matchOperator; MatchOperator = matchOperator;
} }
/// <inheritdoc cref="IStringMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
Func<string?, bool> equals = IgnoreCase Func<string?, bool> equals = IgnoreCase
? pattern => string.Equals(pattern, input, StringComparison.OrdinalIgnoreCase) ? pattern => string.Equals(pattern, input, StringComparison.OrdinalIgnoreCase)
: pattern => pattern == input; : pattern => pattern == input;
double score = MatchScores.ToScore(_values.Select(v => equals(v)).ToArray(), MatchOperator); var score = MatchScores.ToScore(_values.Select(v => equals(v)).ToArray(), MatchOperator);
return MatchBehaviourHelper.Convert(MatchBehaviour, score); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score));
} }
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> /// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns() public AnyOf<string, StringPattern>[] GetPatterns()
{ {
return _values; return _values;
@@ -80,7 +74,7 @@ public class ExactMatcher : IStringMatcher, IIgnoreCaseMatcher
/// <inheritdoc /> /// <inheritdoc />
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc />
public string Name => "ExactMatcher"; public string Name => "ExactMatcher";
/// <inheritdoc /> /// <inheritdoc />
@@ -19,12 +19,9 @@ public class ExactObjectMatcher : IObjectMatcher
/// </summary> /// </summary>
public byte[]? ValueAsBytes { get; } public byte[]? ValueAsBytes { get; }
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class. /// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary> /// </summary>
@@ -56,17 +53,15 @@ public class ExactObjectMatcher : IObjectMatcher
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class. /// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, byte[] value, bool throwException = false) public ExactObjectMatcher(MatchBehaviour matchBehaviour, byte[] value)
{ {
ValueAsBytes = Guard.NotNull(value); ValueAsBytes = Guard.NotNull(value);
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
} }
/// <inheritdoc cref="IObjectMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(object? input) public MatchResult IsMatch(object? input)
{ {
bool equals = false; bool equals = false;
if (ValueAsObject != null) if (ValueAsObject != null)
@@ -81,6 +76,6 @@ public class ExactObjectMatcher : IObjectMatcher
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals)); return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
} }
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc />
public string Name => "ExactObjectMatcher"; public string Name => "ExactObjectMatcher";
} }
+44 -38
View File
@@ -1,12 +1,14 @@
#if GRAPHQL #if GRAPHQL
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using AnyOfTypes; using AnyOfTypes;
using GraphQL; using GraphQL;
using GraphQL.Types; using GraphQL.Types;
using Newtonsoft.Json; using Newtonsoft.Json;
using Stef.Validation; using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -19,8 +21,10 @@ public class GraphQLMatcher : IStringMatcher
{ {
private sealed class GraphQLRequest private sealed class GraphQLRequest
{ {
// ReSharper disable once UnusedAutoPropertyAccessor.Local
public string? Query { get; set; } public string? Query { get; set; }
// ReSharper disable once UnusedAutoPropertyAccessor.Local
public Dictionary<string, object?>? Variables { get; set; } public Dictionary<string, object?>? Variables { get; set; }
} }
@@ -31,21 +35,16 @@ public class GraphQLMatcher : IStringMatcher
/// <inheritdoc /> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc />
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LinqMatcher"/> class. /// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary> /// </summary>
/// <param name="schema">The schema.</param> /// <param name="schema">The schema.</param>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
public GraphQLMatcher(AnyOf<string, StringPattern, ISchema> schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, bool throwException = false, MatchOperator matchOperator = MatchOperator.Or) public GraphQLMatcher(AnyOf<string, StringPattern, ISchema> schema, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, MatchOperator matchOperator = MatchOperator.Or)
{ {
Guard.NotNull(schema); Guard.NotNull(schema);
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator; MatchOperator = matchOperator;
var patterns = new List<AnyOf<string, StringPattern>>(); var patterns = new List<AnyOf<string, StringPattern>>();
@@ -72,51 +71,44 @@ public class GraphQLMatcher : IStringMatcher
} }
/// <inheritdoc /> /// <inheritdoc />
public double IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
var match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? exception = null;
try if (input != null && TryGetGraphQLRequest(input, out var graphQLRequest))
{ {
var graphQLRequest = JsonConvert.DeserializeObject<GraphQLRequest>(input!)!; try
var executionResult = new DocumentExecuter().ExecuteAsync(_ =>
{ {
_.ThrowOnUnhandledException = true; var executionResult = new DocumentExecuter().ExecuteAsync(_ =>
_.Schema = _schema;
_.Query = graphQLRequest.Query;
if (graphQLRequest.Variables != null)
{ {
_.Variables = new Inputs(graphQLRequest.Variables); _.ThrowOnUnhandledException = true;
}
}).GetAwaiter().GetResult();
if (executionResult.Errors == null || executionResult.Errors.Count == 0) _.Schema = _schema;
{ _.Query = graphQLRequest.Query;
match = MatchScores.Perfect;
} if (graphQLRequest.Variables != null)
else {
{ _.Variables = new Inputs(graphQLRequest.Variables);
var exceptions = executionResult.Errors.OfType<Exception>().ToArray(); }
if (exceptions.Length == 1) }).GetAwaiter().GetResult();
if (executionResult.Errors == null || executionResult.Errors.Count == 0)
{ {
throw exceptions[0]; score = MatchScores.Perfect;
}
else
{
exception = executionResult.Errors.OfType<Exception>().ToArray().ToException();
} }
throw new AggregateException(exceptions);
} }
} catch (Exception ex)
catch
{
if (ThrowException)
{ {
throw; exception = ex;
} }
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -131,6 +123,20 @@ public class GraphQLMatcher : IStringMatcher
/// <inheritdoc /> /// <inheritdoc />
public string Name => nameof(GraphQLMatcher); public string Name => nameof(GraphQLMatcher);
private static bool TryGetGraphQLRequest(string input, [NotNullWhen(true)] out GraphQLRequest? graphQLRequest)
{
try
{
graphQLRequest = JsonConvert.DeserializeObject<GraphQLRequest>(input);
return graphQLRequest != null;
}
catch
{
graphQLRequest = default;
return false;
}
}
private static ISchema BuildSchema(string schema) private static ISchema BuildSchema(string schema)
{ {
return Schema.For(schema); return Schema.For(schema);
@@ -6,7 +6,7 @@ namespace WireMock.Matchers.Helpers;
internal static class BodyDataMatchScoreCalculator internal static class BodyDataMatchScoreCalculator
{ {
public static double CalculateMatchScore(IBodyData? requestMessage, IMatcher matcher) public static MatchResult CalculateMatchScore(IBodyData? requestMessage, IMatcher matcher)
{ {
Guard.NotNull(matcher); Guard.NotNull(matcher);
@@ -23,7 +23,7 @@ internal static class BodyDataMatchScoreCalculator
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsBytes); return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsBytes);
default: default:
return MatchScores.Mismatch; return default;
} }
} }
@@ -63,16 +63,6 @@ internal static class BodyDataMatchScoreCalculator
} }
} }
#if MIMEKIT_XXX return default;
if (matcher is MultiPartMatcher multiPartMatcher)
{
// If the body is a String or MultiPart, use the BodyAsString to match on.
if (requestMessage?.DetectedBodyType is BodyType.String or BodyType.MultiPart)
{
return multiPartMatcher.IsMatch(requestMessage.BodyAsString);
}
}
#endif
return MatchScores.Mismatch;
} }
} }
-5
View File
@@ -14,9 +14,4 @@ public interface IMatcher
/// Gets the match behaviour. /// Gets the match behaviour.
/// </summary> /// </summary>
MatchBehaviour MatchBehaviour { get; } MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Should this matcher throw an exception?
/// </summary>
bool ThrowException { get; }
} }
+2 -2
View File
@@ -9,6 +9,6 @@ public interface IObjectMatcher : IMatcher
/// Determines whether the specified input is match. /// Determines whether the specified input is match.
/// </summary> /// </summary>
/// <param name="input">The input.</param> /// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns> /// <returns>MatchResult</returns>
double IsMatch(object? input); MatchResult IsMatch(object? input);
} }
+2 -2
View File
@@ -13,8 +13,8 @@ public interface IStringMatcher : IMatcher
/// Determines whether the specified input is match. /// Determines whether the specified input is match.
/// </summary> /// </summary>
/// <param name="input">The input.</param> /// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns> /// <returns>MatchResult</returns>
double IsMatch(string? input); MatchResult IsMatch(string? input);
/// <summary> /// <summary>
/// Gets the patterns. /// Gets the patterns.
+26 -32
View File
@@ -1,6 +1,6 @@
using System;
using System.Linq; using System.Linq;
using AnyOfTypes; using AnyOfTypes;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Stef.Validation; using Stef.Validation;
using WireMock.Extensions; using WireMock.Extensions;
@@ -17,17 +17,15 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
{ {
private readonly AnyOf<string, StringPattern>[] _patterns; private readonly AnyOf<string, StringPattern>[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class. /// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
public JsonPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns.ToAnyOfPatterns()) public JsonPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or,
patterns.ToAnyOfPatterns())
{ {
} }
@@ -35,7 +33,8 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class. /// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
public JsonPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns) public JsonPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch,
MatchOperator.Or, patterns)
{ {
} }
@@ -43,48 +42,45 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class. /// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
public JsonPathMatcher( public JsonPathMatcher(
MatchBehaviour matchBehaviour, MatchBehaviour matchBehaviour,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or, MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] patterns) params AnyOf<string, StringPattern>[] patterns)
{ {
_patterns = Guard.NotNull(patterns); _patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator; MatchOperator = matchOperator;
} }
/// <inheritdoc cref="IStringMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
double match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? exception = null;
if (input != null) if (input != null)
{ {
try try
{ {
var jToken = JToken.Parse(input); var jToken = JToken.Parse(input);
match = IsMatch(jToken); score = IsMatch(jToken);
} }
catch (JsonException) catch (Exception ex)
{ {
if (ThrowException) exception = ex;
{
throw;
}
} }
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
} }
/// <inheritdoc cref="IObjectMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(object? input) public MatchResult IsMatch(object? input)
{ {
double match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? exception = null;
// When input is null or byte[], return Mismatch. // When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[])) if (input != null && !(input is byte[]))
@@ -93,18 +89,15 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
{ {
// Check if JToken or object // Check if JToken or object
JToken jToken = input as JToken ?? JObject.FromObject(input); JToken jToken = input as JToken ?? JObject.FromObject(input);
match = IsMatch(jToken); score = IsMatch(jToken);
} }
catch (JsonException) catch (Exception ex)
{ {
if (ThrowException) exception = ex;
{
throw;
}
} }
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -116,7 +109,7 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
/// <inheritdoc /> /// <inheritdoc />
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc />
public string Name => "JsonPathMatcher"; public string Name => "JsonPathMatcher";
private double IsMatch(JToken jToken) private double IsMatch(JToken jToken)
@@ -125,7 +118,8 @@ public class JsonPathMatcher : IStringMatcher, IObjectMatcher
// The SelectToken method can accept a string path to a child token ( i.e. "Manufacturers[0].Products[0].Price"). // The SelectToken method can accept a string path to a child token ( i.e. "Manufacturers[0].Products[0].Price").
// In that case it will return a JValue (some type) which does not implement the IEnumerable interface. // In that case it will return a JValue (some type) which does not implement the IEnumerable interface.
return MatchScores.ToScore(_patterns.Select(pattern => array.SelectToken(pattern.GetPattern()) != null).ToArray(), MatchOperator); return MatchScores.ToScore(
_patterns.Select(pattern => array.SelectToken(pattern.GetPattern()) != null).ToArray(), MatchOperator);
} }
// https://github.com/WireMock-Net/WireMock.Net/issues/965 // https://github.com/WireMock-Net/WireMock.Net/issues/965
+23 -30
View File
@@ -1,3 +1,4 @@
using System;
using System.Linq; using System.Linq;
using AnyOfTypes; using AnyOfTypes;
using DevLab.JmesPath; using DevLab.JmesPath;
@@ -15,17 +16,14 @@ public class JmesPathMatcher : IStringMatcher, IObjectMatcher
{ {
private readonly AnyOf<string, StringPattern>[] _patterns; private readonly AnyOf<string, StringPattern>[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class. /// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
public JmesPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns.ToAnyOfPatterns()) public JmesPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns.ToAnyOfPatterns())
{ {
} }
@@ -33,18 +31,17 @@ public class JmesPathMatcher : IStringMatcher, IObjectMatcher
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class. /// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
public JmesPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns) public JmesPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class. /// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
public JmesPathMatcher(bool throwException = false, MatchOperator matchOperator = MatchOperator.Or, params AnyOf<string, StringPattern>[] patterns) : public JmesPathMatcher(MatchOperator matchOperator = MatchOperator.Or, params AnyOf<string, StringPattern>[] patterns) :
this(MatchBehaviour.AcceptOnMatch, throwException, matchOperator, patterns) this(MatchBehaviour.AcceptOnMatch, matchOperator, patterns)
{ {
} }
@@ -52,60 +49,56 @@ public class JmesPathMatcher : IStringMatcher, IObjectMatcher
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class. /// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
public JmesPathMatcher( public JmesPathMatcher(
MatchBehaviour matchBehaviour, MatchBehaviour matchBehaviour,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or, MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] patterns) params AnyOf<string, StringPattern>[] patterns)
{ {
_patterns = Guard.NotNull(patterns); _patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator; MatchOperator = matchOperator;
} }
/// <inheritdoc cref="IStringMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
double match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? exception = null;
if (input != null) if (input != null)
{ {
try try
{ {
var results = _patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern.GetPattern()))).ToArray(); var results = _patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern.GetPattern()))).ToArray();
match = MatchScores.ToScore(results, MatchOperator); score = MatchScores.ToScore(results, MatchOperator);
} }
catch (JsonException) catch (Exception ex)
{ {
if (ThrowException) exception = ex;
{
throw;
}
} }
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
} }
/// <inheritdoc cref="IObjectMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(object? input) public MatchResult IsMatch(object? input)
{ {
double match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
// When input is null or byte[], return Mismatch. // When input is null or byte[], return Mismatch.
if (input != null && !(input is byte[])) if (input != null && !(input is byte[]))
{ {
string inputAsString = JsonConvert.SerializeObject(input); var inputAsString = JsonConvert.SerializeObject(input);
return IsMatch(inputAsString); return IsMatch(inputAsString);
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return MatchBehaviourHelper.Convert(MatchBehaviour, score);
} }
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> /// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns() public AnyOf<string, StringPattern>[] GetPatterns()
{ {
return _patterns; return _patterns;
@@ -114,6 +107,6 @@ public class JmesPathMatcher : IStringMatcher, IObjectMatcher
/// <inheritdoc /> /// <inheritdoc />
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc />
public string Name => "JmesPathMatcher"; public string Name => nameof(JmesPathMatcher);
} }
+14 -25
View File
@@ -1,7 +1,6 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Linq; using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Stef.Validation; using Stef.Validation;
using WireMock.Util; using WireMock.Util;
@@ -13,21 +12,18 @@ namespace WireMock.Matchers;
/// </summary> /// </summary>
public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
{ {
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc />
public virtual string Name => "JsonMatcher"; public virtual string Name => "JsonMatcher";
/// <inheritdoc cref="IValueMatcher.Value"/> /// <inheritdoc cref="IValueMatcher.Value"/>
public object Value { get; } public object Value { get; }
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/> /// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/>
public bool IgnoreCase { get; } public bool IgnoreCase { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
private readonly JToken _valueAsJToken; private readonly JToken _valueAsJToken;
private readonly Func<JToken, JToken> _jTokenConverter; private readonly Func<JToken, JToken> _jTokenConverter;
@@ -36,8 +32,7 @@ public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
/// </summary> /// </summary>
/// <param name="value">The string value to check for equality.</param> /// <param name="value">The string value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param> /// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param> public JsonMatcher(string value, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase)
public JsonMatcher(string value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
{ {
} }
@@ -46,8 +41,7 @@ public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
/// </summary> /// </summary>
/// <param name="value">The object value to check for equality.</param> /// <param name="value">The object value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param> /// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param> public JsonMatcher(object value, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase)
public JsonMatcher(object value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
{ {
} }
@@ -57,24 +51,23 @@ public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value to check for equality.</param> /// <param name="value">The value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param> /// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param> public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false)
public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false)
{ {
Guard.NotNull(value, nameof(value)); Guard.NotNull(value, nameof(value));
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
IgnoreCase = ignoreCase; IgnoreCase = ignoreCase;
ThrowException = throwException;
Value = value; Value = value;
_valueAsJToken = ConvertValueToJToken(value); _valueAsJToken = ConvertValueToJToken(value);
_jTokenConverter = ignoreCase ? Rename : jToken => jToken; _jTokenConverter = ignoreCase ? Rename : jToken => jToken;
} }
/// <inheritdoc cref="IObjectMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(object? input) public MatchResult IsMatch(object? input)
{ {
bool match = false; var score = MatchScores.Mismatch;
Exception? error = null;
// When input is null or byte[], return Mismatch. // When input is null or byte[], return Mismatch.
if (input != null && input is not byte[]) if (input != null && input is not byte[])
@@ -83,20 +76,16 @@ public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
{ {
var inputAsJToken = ConvertValueToJToken(input); var inputAsJToken = ConvertValueToJToken(input);
match = IsMatch( var match = IsMatch(_jTokenConverter(_valueAsJToken), _jTokenConverter(inputAsJToken));
_jTokenConverter(_valueAsJToken), score = MatchScores.ToScore(match);
_jTokenConverter(inputAsJToken));
} }
catch (JsonException) catch (Exception ex)
{ {
if (ThrowException) error = ex;
{
throw;
}
} }
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match)); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
} }
/// <summary> /// <summary>
@@ -9,27 +9,27 @@ public class JsonPartialMatcher : AbstractJsonPartialMatcher
public override string Name => nameof(JsonPartialMatcher); public override string Name => nameof(JsonPartialMatcher);
/// <inheritdoc /> /// <inheritdoc />
public JsonPartialMatcher(string value, bool ignoreCase = false, bool throwException = false, bool regex = false) public JsonPartialMatcher(string value, bool ignoreCase = false, bool regex = false)
: base(value, ignoreCase, throwException, regex) : base(value, ignoreCase, regex)
{ {
} }
/// <inheritdoc /> /// <inheritdoc />
public JsonPartialMatcher(object value, bool ignoreCase = false, bool throwException = false, bool regex = false) public JsonPartialMatcher(object value, bool ignoreCase = false, bool regex = false)
: base(value, ignoreCase, throwException, regex) : base(value, ignoreCase, regex)
{ {
} }
/// <inheritdoc /> /// <inheritdoc />
public JsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false, bool regex = false) public JsonPartialMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false)
: base(matchBehaviour, value, ignoreCase, throwException, regex) : base(matchBehaviour, value, ignoreCase, regex)
{ {
} }
/// <inheritdoc /> /// <inheritdoc />
protected override bool IsMatch(string value, string input) protected override bool IsMatch(string value, string input)
{ {
var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, IgnoreCase, ThrowException, MatchOperator.Or, value); var exactStringMatcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, IgnoreCase, MatchOperator.Or, value);
return MatchScores.IsPerfect(exactStringMatcher.IsMatch(input)); return exactStringMatcher.IsMatch(input).IsPerfect();
} }
} }
@@ -9,20 +9,20 @@ public class JsonPartialWildcardMatcher : AbstractJsonPartialMatcher
public override string Name => nameof(JsonPartialWildcardMatcher); public override string Name => nameof(JsonPartialWildcardMatcher);
/// <inheritdoc /> /// <inheritdoc />
public JsonPartialWildcardMatcher(string value, bool ignoreCase = false, bool throwException = false, bool regex = false) public JsonPartialWildcardMatcher(string value, bool ignoreCase = false, bool regex = false)
: base(value, ignoreCase, throwException, regex) : base(value, ignoreCase, regex)
{ {
} }
/// <inheritdoc /> /// <inheritdoc />
public JsonPartialWildcardMatcher(object value, bool ignoreCase = false, bool throwException = false, bool regex = false) public JsonPartialWildcardMatcher(object value, bool ignoreCase = false, bool regex = false)
: base(value, ignoreCase, throwException, regex) : base(value, ignoreCase, regex)
{ {
} }
/// <inheritdoc /> /// <inheritdoc />
public JsonPartialWildcardMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool throwException = false, bool regex = false) public JsonPartialWildcardMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false)
: base(matchBehaviour, value, ignoreCase, throwException, regex) : base(matchBehaviour, value, ignoreCase, regex)
{ {
} }
@@ -30,6 +30,6 @@ public class JsonPartialWildcardMatcher : AbstractJsonPartialMatcher
protected override bool IsMatch(string value, string input) protected override bool IsMatch(string value, string input)
{ {
var wildcardStringMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, value, IgnoreCase); var wildcardStringMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, value, IgnoreCase);
return MatchScores.IsPerfect(wildcardStringMatcher.IsMatch(input)); return wildcardStringMatcher.IsMatch(input).IsPerfect();
} }
} }
+20 -33
View File
@@ -1,3 +1,4 @@
using System;
using System.Linq; using System.Linq;
using System.Linq.Dynamic.Core; using System.Linq.Dynamic.Core;
using AnyOfTypes; using AnyOfTypes;
@@ -18,12 +19,9 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
{ {
private readonly AnyOf<string, StringPattern>[] _patterns; private readonly AnyOf<string, StringPattern>[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LinqMatcher"/> class. /// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary> /// </summary>
@@ -36,7 +34,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
/// Initializes a new instance of the <see cref="LinqMatcher"/> class. /// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary> /// </summary>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
public LinqMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns) public LinqMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
{ {
} }
@@ -45,7 +43,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
public LinqMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern) : this(matchBehaviour, false, MatchOperator.Or, pattern) public LinqMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern) : this(matchBehaviour, MatchOperator.Or, pattern)
{ {
} }
@@ -53,25 +51,23 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
/// Initializes a new instance of the <see cref="LinqMatcher"/> class. /// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
public LinqMatcher( public LinqMatcher(
MatchBehaviour matchBehaviour, MatchBehaviour matchBehaviour,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or, MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] patterns) params AnyOf<string, StringPattern>[] patterns)
{ {
_patterns = Guard.NotNull(patterns); _patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator; MatchOperator = matchOperator;
} }
/// <inheritdoc /> /// <inheritdoc />
public double IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
double match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? error = null;
// Convert a single input string to a Queryable string-list with 1 entry. // Convert a single input string to a Queryable string-list with 1 entry.
IQueryable queryable = new[] { input }.AsQueryable(); IQueryable queryable = new[] { input }.AsQueryable();
@@ -79,25 +75,21 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
try try
{ {
// Use the Any(...) method to check if the result matches // Use the Any(...) method to check if the result matches
match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern.GetPattern())).ToArray(), MatchOperator); score = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern.GetPattern())).ToArray(), MatchOperator);
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
} }
catch catch (Exception e)
{ {
if (ThrowException) error = e;
{
throw;
}
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
} }
/// <inheritdoc /> /// <inheritdoc />
public double IsMatch(object? input) public MatchResult IsMatch(object? input)
{ {
double match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? error = null;
JArray jArray; JArray jArray;
try try
@@ -106,7 +98,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
} }
catch catch
{ {
jArray = new JArray { JToken.FromObject(input) }; jArray = input == null ? new JArray() : new JArray { JToken.FromObject(input) };
} }
// Convert a single object to a Queryable JObject-list with 1 entry. // Convert a single object to a Queryable JObject-list with 1 entry.
@@ -117,19 +109,14 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
var patternsAsStringArray = _patterns.Select(p => p.GetPattern()).ToArray(); var patternsAsStringArray = _patterns.Select(p => p.GetPattern()).ToArray();
var scores = patternsAsStringArray.Select(p => queryable.Any(p)).ToArray(); var scores = patternsAsStringArray.Select(p => queryable.Any(p)).ToArray();
match = MatchScores.ToScore(scores, MatchOperator); score = MatchScores.ToScore(scores, MatchOperator);
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
} }
catch catch (Exception e)
{ {
if (ThrowException) error = e;
{
throw;
}
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -142,5 +129,5 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
public MatchOperator MatchOperator { get; } public MatchOperator MatchOperator { get; }
/// <inheritdoc /> /// <inheritdoc />
public string Name => "LinqMatcher"; public string Name => nameof(LinqMatcher);
} }
+89
View File
@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Stef.Validation;
using WireMock.Extensions;
namespace WireMock.Matchers;
/// <summary>
/// The MatchResult which contains the score (value between 0.0 - 1.0 of the similarity) and an optional error message.
/// </summary>
public struct MatchResult
{
/// <summary>
/// A value between 0.0 - 1.0 of the similarity.
/// </summary>
public double Score { get; set; }
/// <summary>
/// The exception message) in case the matching fails.
/// [Optional]
/// </summary>
public Exception? Exception { get; set; }
/// <summary>
/// Create a MatchResult
/// </summary>
/// <param name="score">A value between 0.0 - 1.0 of the similarity.</param>
/// <param name="exception">The exception in case the matching fails. [Optional]</param>
public MatchResult(double score, Exception? exception = null)
{
Score = score;
Exception = exception;
}
/// <summary>
/// Create a MatchResult
/// </summary>
/// <param name="exception">The exception in case the matching fails.</param>
public MatchResult(Exception exception)
{
Exception = Guard.NotNull(exception);
}
/// <summary>
/// Implicitly converts a double to a MatchResult.
/// </summary>
/// <param name="score">The score</param>
public static implicit operator MatchResult(double score)
{
return new MatchResult(score);
}
/// <summary>
/// Is the value a perfect match?
/// </summary>
public bool IsPerfect() => MatchScores.IsPerfect(Score);
/// <summary>
/// Create a MatchResult from multiple MatchResults.
/// </summary>
/// <param name="matchResults">A list of MatchResults.</param>
/// <param name="matchOperator">The MatchOperator</param>
/// <returns>MatchResult</returns>
public static MatchResult From(IReadOnlyList<MatchResult> matchResults, MatchOperator matchOperator)
{
Guard.NotNullOrEmpty(matchResults);
if (matchResults.Count == 1)
{
return matchResults[0];
}
return new MatchResult
{
Score = MatchScores.ToScore(matchResults.Select(r => r.Score).ToArray(), matchOperator),
Exception = matchResults.Select(m => m.Exception).OfType<Exception>().ToArray().ToException()
};
}
/// <summary>
/// Expand to Tuple
/// </summary>
/// <returns>Tuple : Score and Exception</returns>
public (double Score, Exception? Exception) Expand()
{
return (Score, Exception);
}
}
+13 -18
View File
@@ -1,7 +1,9 @@
#if MIMEKIT #if MIMEKIT
using System; using System;
using MimeKit; using MimeKit;
using WireMock.Matchers;
using WireMock.Matchers.Helpers; using WireMock.Matchers.Helpers;
using WireMock.Models;
using WireMock.Util; using WireMock.Util;
namespace WireMock.Matchers; namespace WireMock.Matchers;
@@ -11,7 +13,7 @@ namespace WireMock.Matchers;
/// </summary> /// </summary>
public class MimePartMatcher : IMatcher public class MimePartMatcher : IMatcher
{ {
private readonly Func<MimePart, double>[] _funcs; private readonly Func<MimePart, MatchResult>[] _funcs;
/// <inheritdoc /> /// <inheritdoc />
public string Name => nameof(MimePartMatcher); public string Name => nameof(MimePartMatcher);
@@ -39,9 +41,6 @@ public class MimePartMatcher : IMatcher
/// <inheritdoc /> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc />
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MimePartMatcher"/> class. /// Initializes a new instance of the <see cref="MimePartMatcher"/> class.
/// </summary> /// </summary>
@@ -50,8 +49,7 @@ public class MimePartMatcher : IMatcher
IStringMatcher? contentTypeMatcher, IStringMatcher? contentTypeMatcher,
IStringMatcher? contentDispositionMatcher, IStringMatcher? contentDispositionMatcher,
IStringMatcher? contentTransferEncodingMatcher, IStringMatcher? contentTransferEncodingMatcher,
IMatcher? contentMatcher, IMatcher? contentMatcher
bool throwException = false
) )
{ {
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
@@ -59,7 +57,6 @@ public class MimePartMatcher : IMatcher
ContentDispositionMatcher = contentDispositionMatcher; ContentDispositionMatcher = contentDispositionMatcher;
ContentTransferEncodingMatcher = contentTransferEncodingMatcher; ContentTransferEncodingMatcher = contentTransferEncodingMatcher;
ContentMatcher = contentMatcher; ContentMatcher = contentMatcher;
ThrowException = throwException;
_funcs = new[] _funcs = new[]
{ {
@@ -75,29 +72,27 @@ public class MimePartMatcher : IMatcher
/// </summary> /// </summary>
/// <param name="mimePart">The MimePart.</param> /// <param name="mimePart">The MimePart.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns> /// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
public double IsMatch(MimePart mimePart) public MatchResult IsMatch(MimePart mimePart)
{ {
var match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? exception = null;
try try
{ {
if (Array.TrueForAll(_funcs, func => MatchScores.IsPerfect(func(mimePart)))) if (Array.TrueForAll(_funcs, func => func(mimePart).IsPerfect()))
{ {
match = MatchScores.Perfect; score = MatchScores.Perfect;
} }
} }
catch catch (Exception ex)
{ {
if (ThrowException) exception = ex;
{
throw;
}
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
} }
private double MatchOnContent(MimePart mimePart) private MatchResult MatchOnContent(MimePart mimePart)
{ {
if (ContentMatcher == null) if (ContentMatcher == null)
{ {
@@ -11,15 +11,12 @@ namespace WireMock.Matchers;
/// <seealso cref="IObjectMatcher" /> /// <seealso cref="IObjectMatcher" />
public class NotNullOrEmptyMatcher : IObjectMatcher, IStringMatcher public class NotNullOrEmptyMatcher : IObjectMatcher, IStringMatcher
{ {
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc />
public string Name => "NotNullOrEmptyMatcher"; public string Name => nameof(NotNullOrEmptyMatcher);
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NotNullOrEmptyMatcher"/> class. /// Initializes a new instance of the <see cref="NotNullOrEmptyMatcher"/> class.
/// </summary> /// </summary>
@@ -29,8 +26,8 @@ public class NotNullOrEmptyMatcher : IObjectMatcher, IStringMatcher
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
} }
/// <inheritdoc cref="IObjectMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(object? input) public MatchResult IsMatch(object? input)
{ {
bool match; bool match;
@@ -52,15 +49,15 @@ public class NotNullOrEmptyMatcher : IObjectMatcher, IStringMatcher
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match)); return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
} }
/// <inheritdoc cref="IStringMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
var match = !string.IsNullOrEmpty(input); var match = !string.IsNullOrEmpty(input);
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match)); return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
} }
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> /// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns() public AnyOf<string, StringPattern>[] GetPatterns()
{ {
return EmptyArray<AnyOf<string, StringPattern>>.Value; return EmptyArray<AnyOf<string, StringPattern>>.Value;
+12 -23
View File
@@ -20,27 +20,22 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
private readonly AnyOf<string, StringPattern>[] _patterns; private readonly AnyOf<string, StringPattern>[] _patterns;
private readonly Regex[] _expressions; private readonly Regex[] _expressions;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RegexMatcher"/> class. /// Initializes a new instance of the <see cref="RegexMatcher"/> class.
/// </summary> /// </summary>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param> /// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="useRegexExtended">Use RegexExtended (default = true).</param> /// <param name="useRegexExtended">Use RegexExtended (default = true).</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
public RegexMatcher( public RegexMatcher(
[RegexPattern] AnyOf<string, StringPattern> pattern, [RegexPattern] AnyOf<string, StringPattern> pattern,
bool ignoreCase = false, bool ignoreCase = false,
bool throwException = false,
bool useRegexExtended = true, bool useRegexExtended = true,
MatchOperator matchOperator = MatchOperator.Or) : MatchOperator matchOperator = MatchOperator.Or) :
this(MatchBehaviour.AcceptOnMatch, new[] { pattern }, ignoreCase, throwException, useRegexExtended, matchOperator) this(MatchBehaviour.AcceptOnMatch, new[] { pattern }, ignoreCase, useRegexExtended, matchOperator)
{ {
} }
@@ -50,17 +45,15 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param> /// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="useRegexExtended">Use RegexExtended (default = true).</param> /// <param name="useRegexExtended">Use RegexExtended (default = true).</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
public RegexMatcher( public RegexMatcher(
MatchBehaviour matchBehaviour, MatchBehaviour matchBehaviour,
[RegexPattern] AnyOf<string, StringPattern> pattern, [RegexPattern] AnyOf<string, StringPattern> pattern,
bool ignoreCase = false, bool ignoreCase = false,
bool throwException = false,
bool useRegexExtended = true, bool useRegexExtended = true,
MatchOperator matchOperator = MatchOperator.Or) : MatchOperator matchOperator = MatchOperator.Or) :
this(matchBehaviour, new[] { pattern }, ignoreCase, throwException, useRegexExtended, matchOperator) this(matchBehaviour, new[] { pattern }, ignoreCase, useRegexExtended, matchOperator)
{ {
} }
@@ -70,21 +63,18 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param> /// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="useRegexExtended">Use RegexExtended (default = true).</param> /// <param name="useRegexExtended">Use RegexExtended (default = true).</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
public RegexMatcher( public RegexMatcher(
MatchBehaviour matchBehaviour, MatchBehaviour matchBehaviour,
[RegexPattern] AnyOf<string, StringPattern>[] patterns, [RegexPattern] AnyOf<string, StringPattern>[] patterns,
bool ignoreCase = false, bool ignoreCase = false,
bool throwException = false,
bool useRegexExtended = true, bool useRegexExtended = true,
MatchOperator matchOperator = MatchOperator.Or) MatchOperator matchOperator = MatchOperator.Or)
{ {
_patterns = Guard.NotNull(patterns); _patterns = Guard.NotNull(patterns);
IgnoreCase = ignoreCase; IgnoreCase = ignoreCase;
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator; MatchOperator = matchOperator;
RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline; RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline;
@@ -97,26 +87,25 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
_expressions = patterns.Select(p => useRegexExtended ? new RegexExtended(p.GetPattern(), options) : new Regex(p.GetPattern(), options)).ToArray(); _expressions = patterns.Select(p => useRegexExtended ? new RegexExtended(p.GetPattern(), options) : new Regex(p.GetPattern(), options)).ToArray();
} }
/// <inheritdoc cref="IStringMatcher.IsMatch"/> /// <inheritdoc />
public virtual double IsMatch(string? input) public virtual MatchResult IsMatch(string? input)
{ {
double match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? exception = null;
if (input != null) if (input != null)
{ {
try try
{ {
match = MatchScores.ToScore(_expressions.Select(e => e.IsMatch(input)).ToArray(), MatchOperator); score = MatchScores.ToScore(_expressions.Select(e => e.IsMatch(input)).ToArray(), MatchOperator);
} }
catch (Exception) catch (Exception ex)
{ {
if (ThrowException) exception = ex;
{
throw;
}
} }
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -9,30 +9,25 @@ namespace WireMock.Matchers.Request;
/// </summary> /// </summary>
public class RequestMatchResult : IRequestMatchResult public class RequestMatchResult : IRequestMatchResult
{ {
/// <inheritdoc cref="IRequestMatchResult.TotalScore" /> /// <inheritdoc />
public double TotalScore => MatchDetails.Sum(md => md.Score); public double TotalScore => MatchDetails.Sum(md => md.Score);
/// <inheritdoc cref="IRequestMatchResult.TotalNumber" /> /// <inheritdoc />
public int TotalNumber => MatchDetails.Count; public int TotalNumber => MatchDetails.Count;
/// <inheritdoc cref="IRequestMatchResult.IsPerfectMatch" /> /// <inheritdoc />
public bool IsPerfectMatch => Math.Abs(TotalScore - TotalNumber) < MatchScores.Tolerance; public bool IsPerfectMatch => Math.Abs(TotalScore - TotalNumber) < MatchScores.Tolerance;
/// <inheritdoc cref="IRequestMatchResult.AverageTotalScore" /> /// <inheritdoc />
public double AverageTotalScore => TotalNumber == 0 ? 0.0 : TotalScore / TotalNumber; public double AverageTotalScore => TotalNumber == 0 ? MatchScores.Mismatch : TotalScore / TotalNumber;
/// <inheritdoc cref="IRequestMatchResult.MatchDetails" /> /// <inheritdoc />
public IList<MatchDetail> MatchDetails { get; } = new List<MatchDetail>(); public IList<MatchDetail> MatchDetails { get; } = new List<MatchDetail>();
/// <summary> /// <inheritdoc />
/// Adds the score. public double AddScore(Type matcherType, double score, Exception? exception)
/// </summary>
/// <param name="matcherType">The matcher Type.</param>
/// <param name="score">The score.</param>
/// <returns>The score.</returns>
public double AddScore(Type matcherType, double score)
{ {
MatchDetails.Add(new MatchDetail { MatcherType = matcherType, Score = score }); MatchDetails.Add(new MatchDetail { MatcherType = matcherType, Score = score, Exception = exception });
return score; return score;
} }
@@ -44,11 +39,16 @@ public class RequestMatchResult : IRequestMatchResult
/// <returns> /// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance precedes <paramref name="obj" /> in the sort order. Zero This instance occurs in the same position in the sort order as <paramref name="obj" />. Greater than zero This instance follows <paramref name="obj" /> in the sort order. /// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance precedes <paramref name="obj" /> in the sort order. Zero This instance occurs in the same position in the sort order as <paramref name="obj" />. Greater than zero This instance follows <paramref name="obj" /> in the sort order.
/// </returns> /// </returns>
public int CompareTo(object obj) public int CompareTo(object? obj)
{ {
if (obj == null)
{
return -1;
}
var compareObj = (RequestMatchResult)obj; var compareObj = (RequestMatchResult)obj;
int averageTotalScoreResult = compareObj.AverageTotalScore.CompareTo(AverageTotalScore); var averageTotalScoreResult = compareObj.AverageTotalScore.CompareTo(AverageTotalScore);
// In case the score is equal, prefer the one with the most matchers. // In case the score is equal, prefer the one with the most matchers.
return averageTotalScoreResult == 0 ? compareObj.TotalNumber.CompareTo(TotalNumber) : averageTotalScoreResult; return averageTotalScoreResult == 0 ? compareObj.TotalNumber.CompareTo(TotalNumber) : averageTotalScoreResult;
@@ -145,16 +145,16 @@ public class RequestMessageBodyMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{ {
double score = CalculateMatchScore(requestMessage); var (score, exception) = CalculateMatchScore(requestMessage).Expand();
return requestMatchResult.AddScore(GetType(), score); return requestMatchResult.AddScore(GetType(), score, exception);
} }
private double CalculateMatchScore(IRequestMessage requestMessage) private MatchResult CalculateMatchScore(IRequestMessage requestMessage)
{ {
if (Matchers != null) if (Matchers != null && Matchers.Any())
{ {
var matchersResult = Matchers.Select(matcher => BodyDataMatchScoreCalculator.CalculateMatchScore(requestMessage.BodyData, matcher)).ToArray(); var results = Matchers.Select(matcher => BodyDataMatchScoreCalculator.CalculateMatchScore(requestMessage.BodyData, matcher)).ToArray();
return MatchScores.ToScore(matchersResult, MatchOperator); return MatchResult.From(results, MatchOperator);
} }
if (Func != null) if (Func != null)
@@ -182,6 +182,6 @@ public class RequestMessageBodyMatcher : IRequestMatcher
return MatchScores.ToScore(BodyDataFunc(requestMessage.BodyData)); return MatchScores.ToScore(BodyDataFunc(requestMessage.BodyData));
} }
return MatchScores.Mismatch; return default;
} }
} }
@@ -43,7 +43,7 @@ public class RequestMessageClientIPMatcher : IRequestMatcher
MatchOperator matchOperator, MatchOperator matchOperator,
params string[] clientIPs) : params string[] clientIPs) :
this(matchBehaviour, matchOperator, clientIPs this(matchBehaviour, matchOperator, clientIPs
.Select(clientIP => new WildcardMatcher(matchBehaviour, new AnyOf<string, StringPattern>[] { clientIP }, false, false, matchOperator)) .Select(clientIP => new WildcardMatcher(matchBehaviour, new AnyOf<string, StringPattern>[] { clientIP }, false, matchOperator))
.Cast<IStringMatcher>().ToArray()) .Cast<IStringMatcher>().ToArray())
{ {
Behaviour = matchBehaviour; Behaviour = matchBehaviour;
@@ -75,16 +75,16 @@ public class RequestMessageClientIPMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); var (score, exception) = GetMatchResult(requestMessage).Expand();
return requestMatchResult.AddScore(GetType(), score); return requestMatchResult.AddScore(GetType(), score, exception);
} }
private double IsMatch(IRequestMessage requestMessage) private MatchResult GetMatchResult(IRequestMessage requestMessage)
{ {
if (Matchers != null) if (Matchers != null)
{ {
var results = Matchers.Select(m => m.IsMatch(requestMessage.ClientIP)).ToArray(); var results = Matchers.Select(m => m.IsMatch(requestMessage.ClientIP)).ToArray();
return MatchScores.ToScore(results, MatchOperator); return MatchResult.From(results, MatchOperator);
} }
if (Funcs != null) if (Funcs != null)
@@ -93,6 +93,6 @@ public class RequestMessageClientIPMatcher : IRequestMatcher
return MatchScores.ToScore(results, MatchOperator); return MatchScores.ToScore(results, MatchOperator);
} }
return MatchScores.Mismatch; return default;
} }
} }
@@ -88,11 +88,11 @@ public class RequestMessageCookieMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); var (score, exception) = GetMatchResult(requestMessage).Expand();
return requestMatchResult.AddScore(GetType(), score); return requestMatchResult.AddScore(GetType(), score, exception);
} }
private double IsMatch(IRequestMessage requestMessage) private MatchResult GetMatchResult(IRequestMessage requestMessage)
{ {
if (requestMessage.Cookies == null) if (requestMessage.Cookies == null)
{ {
@@ -109,7 +109,7 @@ public class RequestMessageCookieMatcher : IRequestMatcher
if (Matchers == null) if (Matchers == null)
{ {
return MatchScores.Mismatch; return default;
} }
if (!cookies.ContainsKey(Name)) if (!cookies.ContainsKey(Name))
@@ -117,7 +117,6 @@ public class RequestMessageCookieMatcher : IRequestMatcher
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch); return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
} }
string value = cookies[Name]; return Matchers.Max(m => m.IsMatch(cookies[Name]));
return Matchers.Max(m => m.IsMatch(value));
} }
} }
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Stef.Validation; using Stef.Validation;
using WireMock.Types; using WireMock.Types;
@@ -64,11 +65,13 @@ public class RequestMessageGraphQLMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{ {
var score = CalculateMatchScore(requestMessage); var results = CalculateMatchResults(requestMessage);
return requestMatchResult.AddScore(GetType(), score); var (score, exception) = MatchResult.From(results, MatchOperator).Expand();
return requestMatchResult.AddScore(GetType(), score, exception);
} }
private static double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher) private static MatchResult CalculateMatchResult(IRequestMessage requestMessage, IMatcher matcher)
{ {
// Check if the matcher is a IStringMatcher // Check if the matcher is a IStringMatcher
// If the body is a Json or a String, use the BodyAsString to match on. // If the body is a Json or a String, use the BodyAsString to match on.
@@ -77,18 +80,12 @@ public class RequestMessageGraphQLMatcher : IRequestMatcher
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString); return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
} }
return MatchScores.Mismatch; return default;
} }
private double CalculateMatchScore(IRequestMessage requestMessage) private IReadOnlyList<MatchResult> CalculateMatchResults(IRequestMessage requestMessage)
{ {
if (Matchers == null) return Matchers == null ? new[] { new MatchResult() } : Matchers.Select(matcher => CalculateMatchResult(requestMessage, matcher)).ToArray();
{
return MatchScores.Mismatch;
}
var matchersResult = Matchers.Select(matcher => CalculateMatchScore(requestMessage, matcher)).ToArray();
return MatchScores.ToScore(matchersResult, MatchOperator);
} }
#if GRAPHQL #if GRAPHQL
@@ -100,11 +100,11 @@ public class RequestMessageHeaderMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); var (score, exception) = GetMatchResult(requestMessage).Expand();
return requestMatchResult.AddScore(GetType(), score); return requestMatchResult.AddScore(GetType(), score, exception);
} }
private double IsMatch(IRequestMessage requestMessage) private MatchResult GetMatchResult(IRequestMessage requestMessage)
{ {
if (requestMessage.Headers == null) if (requestMessage.Headers == null)
{ {
@@ -127,15 +127,15 @@ public class RequestMessageHeaderMatcher : IRequestMatcher
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch); return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
} }
var results = new List<double>(); var results = new List<MatchResult>();
foreach (var matcher in Matchers) foreach (var matcher in Matchers)
{ {
var resultsPerMatcher = headers[Name].Select(v => matcher.IsMatch(v)).ToArray(); var resultsPerMatcher = headers[Name].Select(matcher.IsMatch).ToArray();
results.Add(MatchScores.ToScore(resultsPerMatcher, MatchOperator.And)); results.Add(MatchResult.From(resultsPerMatcher, MatchOperator.And));
} }
return MatchScores.ToScore(results, MatchOperator); return MatchResult.From(results, MatchOperator);
} }
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch); return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
@@ -39,14 +39,9 @@ internal class RequestMessageMethodMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = MatchBehaviourHelper.Convert(MatchBehaviour, IsMatch(requestMessage));
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{ {
var scores = Methods.Select(m => string.Equals(m, requestMessage.Method, StringComparison.OrdinalIgnoreCase)).ToArray(); var scores = Methods.Select(m => string.Equals(m, requestMessage.Method, StringComparison.OrdinalIgnoreCase)).ToArray();
return MatchScores.ToScore(scores, MatchOperator); var score = MatchScores.ToScore(scores, MatchOperator);
return requestMatchResult.AddScore(GetType(), score, null);
} }
} }
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Stef.Validation; using Stef.Validation;
using WireMock.Http;
using WireMock.Util; using WireMock.Util;
namespace WireMock.Matchers.Request; namespace WireMock.Matchers.Request;
@@ -54,27 +54,31 @@ public class RequestMessageMultiPartMatcher : IRequestMatcher
#if !MIMEKIT #if !MIMEKIT
throw new System.NotSupportedException("The MultiPartMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower."); throw new System.NotSupportedException("The MultiPartMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
#else #else
var match = MatchScores.Mismatch; var score = MatchScores.Mismatch;
Exception? exception = null;
if (Matchers?.Any() != true) if (Matchers?.Any() != true)
{ {
return requestMatchResult.AddScore(GetType(), match); return requestMatchResult.AddScore(GetType(), score, null);
}
if (!MimeKitUtils.TryGetMimeMessage(requestMessage, out var message))
{
return requestMatchResult.AddScore(GetType(), score, null);
} }
try try
{ {
var message = MimeKitUtils.GetMimeMessage(requestMessage.BodyData!, requestMessage.Headers![HttpKnownHeaderNames.ContentType].ToString());
var mimePartMatchers = Matchers.OfType<MimePartMatcher>().ToArray(); var mimePartMatchers = Matchers.OfType<MimePartMatcher>().ToArray();
foreach (var mimePart in message.BodyParts.OfType<MimeKit.MimePart>()) foreach (var mimePart in message.BodyParts.OfType<MimeKit.MimePart>())
{ {
var matchesForMimePart = new List<double> { MatchScores.Mismatch }; var matchesForMimePart = new List<MatchResult> { default };
matchesForMimePart.AddRange(mimePartMatchers.Select(matcher => matcher.IsMatch(mimePart))); matchesForMimePart.AddRange(mimePartMatchers.Select(matcher => matcher.IsMatch(mimePart)));
match = matchesForMimePart.Max(); score = matchesForMimePart.Select(m => m.Score).Max();
if (MatchScores.IsPerfect(match)) if (MatchScores.IsPerfect(score))
{ {
if (MatchOperator == MatchOperator.Or) if (MatchOperator == MatchOperator.Or)
{ {
@@ -83,17 +87,17 @@ public class RequestMessageMultiPartMatcher : IRequestMatcher
} }
else else
{ {
match = MatchScores.Mismatch; score = MatchScores.Mismatch;
break; break;
} }
} }
} }
catch catch (Exception ex)
{ {
// Empty exception = ex;
} }
return requestMatchResult.AddScore(GetType(), match); return requestMatchResult.AddScore(GetType(), score, exception);
#endif #endif
} }
} }
@@ -54,7 +54,7 @@ public class RequestMessageParamMatcher : IRequestMatcher
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param> /// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
/// <param name="values">The values.</param> /// <param name="values">The values.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, string key, bool ignoreCase, params string[]? values) : public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, string key, bool ignoreCase, params string[]? values) :
this(matchBehaviour, key, ignoreCase, values?.Select(value => new ExactMatcher(matchBehaviour, ignoreCase, false, MatchOperator.And, value)).Cast<IStringMatcher>().ToArray()) this(matchBehaviour, key, ignoreCase, values?.Select(value => new ExactMatcher(matchBehaviour, ignoreCase, MatchOperator.And, value)).Cast<IStringMatcher>().ToArray())
{ {
} }
@@ -85,11 +85,11 @@ public class RequestMessageParamMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{ {
double score = MatchBehaviourHelper.Convert(MatchBehaviour, IsMatch(requestMessage)); var (score, exception) = GetMatchResult(requestMessage).Expand();
return requestMatchResult.AddScore(GetType(), score); return requestMatchResult.AddScore(GetType(), score, exception);
} }
private double IsMatch(IRequestMessage requestMessage) private MatchResult GetMatchResult(IRequestMessage requestMessage)
{ {
if (Funcs != null) if (Funcs != null)
{ {
@@ -100,7 +100,7 @@ public class RequestMessageParamMatcher : IRequestMatcher
if (valuesPresentInRequestMessage == null) if (valuesPresentInRequestMessage == null)
{ {
// Key is not present at all, just return Mismatch // Key is not present at all, just return Mismatch
return MatchScores.Mismatch; return default;
} }
if (Matchers != null && Matchers.Any()) if (Matchers != null && Matchers.Any())
@@ -115,10 +115,10 @@ public class RequestMessageParamMatcher : IRequestMatcher
return MatchScores.Perfect; return MatchScores.Perfect;
} }
return MatchScores.Mismatch; return default;
} }
private double CalculateScore(IReadOnlyList<IStringMatcher> matchers, WireMockList<string> valuesPresentInRequestMessage) private static MatchResult CalculateScore(IReadOnlyList<IStringMatcher> matchers, WireMockList<string> valuesPresentInRequestMessage)
{ {
var total = new List<double>(); var total = new List<double>();
@@ -130,7 +130,7 @@ public class RequestMessageParamMatcher : IRequestMatcher
double score = 0d; double score = 0d;
foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage) foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage)
{ {
score += matcher.IsMatch(valuePresentInRequestMessage) / matcher.GetPatterns().Length; score += matcher.IsMatch(valuePresentInRequestMessage).Score / matcher.GetPatterns().Length;
} }
total.Add(score); total.Add(score);
@@ -140,11 +140,11 @@ public class RequestMessageParamMatcher : IRequestMatcher
{ {
foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage) foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage)
{ {
double score = matchers.Max(m => m.IsMatch(valuePresentInRequestMessage)); var score = matchers.Max(m => m.IsMatch(valuePresentInRequestMessage).Score);
total.Add(score); total.Add(score);
} }
} }
return total.Any() ? MatchScores.ToScore(total, MatchOperator.Average) : MatchScores.Mismatch; return total.Any() ? MatchScores.ToScore(total, MatchOperator.Average) : default;
} }
} }
@@ -43,7 +43,7 @@ public class RequestMessagePathMatcher : IRequestMatcher
MatchOperator matchOperator, MatchOperator matchOperator,
params string[] paths) : params string[] paths) :
this(matchBehaviour, matchOperator, paths this(matchBehaviour, matchOperator, paths
.Select(path => new WildcardMatcher(matchBehaviour, new AnyOf<string, StringPattern>[] { path }, false, false, matchOperator)) .Select(path => new WildcardMatcher(matchBehaviour, new AnyOf<string, StringPattern>[] { path }, false, matchOperator))
.Cast<IStringMatcher>().ToArray()) .Cast<IStringMatcher>().ToArray())
{ {
Behaviour = matchBehaviour; Behaviour = matchBehaviour;
@@ -75,16 +75,16 @@ public class RequestMessagePathMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); var (score, exception) = GetMatchResult(requestMessage).Expand();
return requestMatchResult.AddScore(GetType(), score); return requestMatchResult.AddScore(GetType(), score, exception);
} }
private double IsMatch(IRequestMessage requestMessage) private MatchResult GetMatchResult(IRequestMessage requestMessage)
{ {
if (Matchers != null) if (Matchers != null)
{ {
var results = Matchers.Select(m => m.IsMatch(requestMessage.Path)).ToArray(); var results = Matchers.Select(m => m.IsMatch(requestMessage.Path)).ToArray();
return MatchScores.ToScore(results, MatchOperator); return MatchResult.From(results, MatchOperator);
} }
if (Funcs != null) if (Funcs != null)
@@ -93,6 +93,6 @@ public class RequestMessagePathMatcher : IRequestMatcher
return MatchScores.ToScore(results, MatchOperator); return MatchScores.ToScore(results, MatchOperator);
} }
return MatchScores.Mismatch; return default;
} }
} }
@@ -30,11 +30,10 @@ internal class RequestMessageScenarioAndStateMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{ {
double score = IsMatch(); return requestMatchResult.AddScore(GetType(), GetScore(), null);
return requestMatchResult.AddScore(GetType(), score);
} }
private double IsMatch() private double GetScore()
{ {
return Equals(_executionConditionState, _nextState) ? MatchScores.Perfect : MatchScores.Mismatch; return Equals(_executionConditionState, _nextState) ? MatchScores.Perfect : MatchScores.Mismatch;
} }
@@ -43,7 +43,7 @@ public class RequestMessageUrlMatcher : IRequestMatcher
MatchOperator matchOperator, MatchOperator matchOperator,
params string[] urls) : params string[] urls) :
this(matchBehaviour, matchOperator, urls this(matchBehaviour, matchOperator, urls
.Select(url => new WildcardMatcher(matchBehaviour, new AnyOf<string, StringPattern>[] { url }, false, false, matchOperator)) .Select(url => new WildcardMatcher(matchBehaviour, new AnyOf<string, StringPattern>[] { url }, false, matchOperator))
.Cast<IStringMatcher>().ToArray()) .Cast<IStringMatcher>().ToArray())
{ {
Behaviour = matchBehaviour; Behaviour = matchBehaviour;
@@ -75,16 +75,16 @@ public class RequestMessageUrlMatcher : IRequestMatcher
/// <inheritdoc /> /// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult) public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{ {
double score = IsMatch(requestMessage); var (score, exception) = GetMatchResult(requestMessage).Expand();
return requestMatchResult.AddScore(GetType(), score); return requestMatchResult.AddScore(GetType(), score, exception);
} }
private double IsMatch(IRequestMessage requestMessage) private MatchResult GetMatchResult(IRequestMessage requestMessage)
{ {
if (Matchers != null) if (Matchers != null)
{ {
var results = Matchers.Select(m => m.IsMatch(requestMessage.Url)).ToArray(); var results = Matchers.Select(m => m.IsMatch(requestMessage.Url)).ToArray();
return MatchScores.ToScore(results, MatchOperator); return MatchResult.From(results, MatchOperator);
} }
if (Funcs != null) if (Funcs != null)
@@ -93,6 +93,6 @@ public class RequestMessageUrlMatcher : IRequestMatcher
return MatchScores.ToScore(results, MatchOperator); return MatchScores.ToScore(results, MatchOperator);
} }
return MatchScores.Mismatch; return default;
} }
} }
+25 -49
View File
@@ -18,12 +18,9 @@ public class SimMetricsMatcher : IStringMatcher
private readonly AnyOf<string, StringPattern>[] _patterns; private readonly AnyOf<string, StringPattern>[] _patterns;
private readonly SimMetricType _simMetricType; private readonly SimMetricType _simMetricType;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class. /// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
/// </summary> /// </summary>
@@ -67,24 +64,21 @@ public class SimMetricsMatcher : IStringMatcher
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="simMetricType">The SimMetric Type</param> /// <param name="simMetricType">The SimMetric Type</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param> /// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
public SimMetricsMatcher( public SimMetricsMatcher(
MatchBehaviour matchBehaviour, MatchBehaviour matchBehaviour,
AnyOf<string, StringPattern>[] patterns, AnyOf<string, StringPattern>[] patterns,
SimMetricType simMetricType = SimMetricType.Levenstein, SimMetricType simMetricType = SimMetricType.Levenstein,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Average) MatchOperator matchOperator = MatchOperator.Average)
{ {
_patterns = Guard.NotNull(patterns); _patterns = Guard.NotNull(patterns);
_simMetricType = simMetricType; _simMetricType = simMetricType;
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator; MatchOperator = matchOperator;
} }
/// <inheritdoc cref="IStringMatcher.IsMatch"/> /// <inheritdoc />
public double IsMatch(string input) public MatchResult IsMatch(string? input)
{ {
IStringMetric stringMetricType = GetStringMetricType(); IStringMetric stringMetricType = GetStringMetricType();
@@ -94,48 +88,30 @@ public class SimMetricsMatcher : IStringMatcher
private IStringMetric GetStringMetricType() private IStringMetric GetStringMetricType()
{ {
switch (_simMetricType) return _simMetricType switch
{ {
case SimMetricType.BlockDistance: SimMetricType.BlockDistance => new BlockDistance(),
return new BlockDistance(); SimMetricType.ChapmanLengthDeviation => new ChapmanLengthDeviation(),
case SimMetricType.ChapmanLengthDeviation: SimMetricType.CosineSimilarity => new CosineSimilarity(),
return new ChapmanLengthDeviation(); SimMetricType.DiceSimilarity => new DiceSimilarity(),
case SimMetricType.CosineSimilarity: SimMetricType.EuclideanDistance => new EuclideanDistance(),
return new CosineSimilarity(); SimMetricType.JaccardSimilarity => new JaccardSimilarity(),
case SimMetricType.DiceSimilarity: SimMetricType.Jaro => new Jaro(),
return new DiceSimilarity(); SimMetricType.JaroWinkler => new JaroWinkler(),
case SimMetricType.EuclideanDistance: SimMetricType.MatchingCoefficient => new MatchingCoefficient(),
return new EuclideanDistance(); SimMetricType.MongeElkan => new MongeElkan(),
case SimMetricType.JaccardSimilarity: SimMetricType.NeedlemanWunch => new NeedlemanWunch(),
return new JaccardSimilarity(); SimMetricType.OverlapCoefficient => new OverlapCoefficient(),
case SimMetricType.Jaro: SimMetricType.QGramsDistance => new QGramsDistance(),
return new Jaro(); SimMetricType.SmithWaterman => new SmithWaterman(),
case SimMetricType.JaroWinkler: SimMetricType.SmithWatermanGotoh => new SmithWatermanGotoh(),
return new JaroWinkler(); SimMetricType.SmithWatermanGotohWindowedAffine => new SmithWatermanGotohWindowedAffine(),
case SimMetricType.MatchingCoefficient: SimMetricType.ChapmanMeanLength => new ChapmanMeanLength(),
return new MatchingCoefficient(); _ => new Levenstein()
case SimMetricType.MongeElkan: };
return new MongeElkan();
case SimMetricType.NeedlemanWunch:
return new NeedlemanWunch();
case SimMetricType.OverlapCoefficient:
return new OverlapCoefficient();
case SimMetricType.QGramsDistance:
return new QGramsDistance();
case SimMetricType.SmithWaterman:
return new SmithWaterman();
case SimMetricType.SmithWatermanGotoh:
return new SmithWatermanGotoh();
case SimMetricType.SmithWatermanGotohWindowedAffine:
return new SmithWatermanGotohWindowedAffine();
case SimMetricType.ChapmanMeanLength:
return new ChapmanMeanLength();
default:
return new Levenstein();
}
} }
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> /// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns() public AnyOf<string, StringPattern>[] GetPatterns()
{ {
return _patterns; return _patterns;
@@ -144,6 +120,6 @@ public class SimMetricsMatcher : IStringMatcher
/// <inheritdoc /> /// <inheritdoc />
public MatchOperator MatchOperator { get; } = MatchOperator.Average; public MatchOperator MatchOperator { get; } = MatchOperator.Average;
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc />
public string Name => $"SimMetricsMatcher.{_simMetricType}"; public string Name => $"SimMetricsMatcher.{_simMetricType}";
} }
+1 -4
View File
@@ -49,15 +49,12 @@ public class WildcardMatcher : RegexMatcher
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase</param> /// <param name="ignoreCase">IgnoreCase</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param> /// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
public WildcardMatcher( public WildcardMatcher(
MatchBehaviour matchBehaviour, MatchBehaviour matchBehaviour,
AnyOf<string, StringPattern>[] patterns, AnyOf<string, StringPattern>[] patterns,
bool ignoreCase = false, bool ignoreCase = false,
bool throwException = false, MatchOperator matchOperator = MatchOperator.Or) : base(matchBehaviour, CreateArray(patterns), ignoreCase, true, matchOperator)
MatchOperator matchOperator = MatchOperator.Or) :
base(matchBehaviour, CreateArray(patterns), ignoreCase, throwException, true, matchOperator)
{ {
_patterns = Guard.NotNull(patterns); _patterns = Guard.NotNull(patterns);
} }
+71 -64
View File
@@ -1,6 +1,8 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Xml; using System.Xml;
using System.Xml.XPath;
using AnyOfTypes; using AnyOfTypes;
using WireMock.Extensions; using WireMock.Extensions;
using WireMock.Models; using WireMock.Models;
@@ -9,86 +11,91 @@ using Stef.Validation;
using Wmhelp.XPath2; using Wmhelp.XPath2;
#endif #endif
namespace WireMock.Matchers namespace WireMock.Matchers;
/// <summary>
/// XPath2Matcher
/// </summary>
/// <seealso cref="IStringMatcher" />
public class XPathMatcher : IStringMatcher
{ {
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; }
/// <summary> /// <summary>
/// XPath2Matcher /// Initializes a new instance of the <see cref="XPathMatcher"/> class.
/// </summary> /// </summary>
/// <seealso cref="IStringMatcher" /> /// <param name="patterns">The patterns.</param>
public class XPathMatcher : IStringMatcher public XPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
{ {
private readonly AnyOf<string, StringPattern>[] _patterns; }
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <summary>
public MatchBehaviour MatchBehaviour { get; } /// Initializes a new instance of the <see cref="XPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="patterns">The patterns.</param>
public XPathMatcher(
MatchBehaviour matchBehaviour,
MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] patterns)
{
_patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour;
MatchOperator = matchOperator;
}
/// <inheritdoc cref="IMatcher.ThrowException"/> /// <inheritdoc />
public bool ThrowException { get; } public MatchResult IsMatch(string? input)
{
var score = MatchScores.Mismatch;
Exception? exception = null;
/// <summary> if (input != null && TryGetXPathNavigator(input, out var nav))
/// Initializes a new instance of the <see cref="XPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public XPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, patterns)
{ {
} try
/// <summary>
/// Initializes a new instance of the <see cref="XPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
/// <param name="patterns">The patterns.</param>
public XPathMatcher(
MatchBehaviour matchBehaviour,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or,
params AnyOf<string, StringPattern>[] patterns)
{
_patterns = Guard.NotNull(patterns);
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
MatchOperator = matchOperator;
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string? input)
{
double match = MatchScores.Mismatch;
if (input != null)
{ {
try
{
var nav = new XmlDocument { InnerXml = input }.CreateNavigator();
#if NETSTANDARD1_3 #if NETSTANDARD1_3
match = MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.Evaluate($"boolean({p.GetPattern()})"))).ToArray(), MatchOperator); score = MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.Evaluate($"boolean({p.GetPattern()})"))).ToArray(), MatchOperator);
#else #else
match = MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.XPath2Evaluate($"boolean({p.GetPattern()})"))).ToArray(), MatchOperator); score = MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.XPath2Evaluate($"boolean({p.GetPattern()})"))).ToArray(), MatchOperator);
#endif #endif
}
catch (Exception)
{
if (ThrowException)
{
throw;
}
}
} }
catch (Exception ex)
return MatchBehaviourHelper.Convert(MatchBehaviour, match); {
exception = ex;
}
} }
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
public AnyOf<string, StringPattern>[] GetPatterns() }
/// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public string Name => nameof(XPathMatcher);
private static bool TryGetXPathNavigator(string input, [NotNullWhen(true)] out XPathNavigator? nav)
{
try
{ {
return _patterns; nav = new XmlDocument { InnerXml = input }.CreateNavigator()!;
return true;
}
catch
{
nav = default;
return false;
} }
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "XPathMatcher";
} }
} }
@@ -67,7 +67,7 @@ namespace WireMock.Owin
catch (Exception ex) catch (Exception ex)
{ {
_options.Logger.Error("HttpStatusCode set to 500 {0}", ex); _options.Logger.Error("HttpStatusCode set to 500 {0}", ex);
await _responseMapper.MapAsync(ResponseMessageBuilder.Create(JsonConvert.SerializeObject(ex), 500), ctx.Response).ConfigureAwait(false); await _responseMapper.MapAsync(ResponseMessageBuilder.Create(500, JsonConvert.SerializeObject(ex)), ctx.Response).ConfigureAwait(false);
} }
} }
} }
@@ -50,7 +50,7 @@ namespace WireMock.Owin.Mappers
_options = Guard.NotNull(options); _options = Guard.NotNull(options);
} }
/// <inheritdoc cref="IOwinResponseMapper.MapAsync"/> /// <inheritdoc />
public async Task MapAsync(IResponseMessage? responseMessage, IResponse response) public async Task MapAsync(IResponseMessage? responseMessage, IResponse response)
{ {
if (responseMessage == null) if (responseMessage == null)
@@ -134,10 +134,8 @@ namespace WireMock.Owin.Mappers
return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(responseMessage.BodyData.BodyAsString!); return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(responseMessage.BodyData.BodyAsString!);
case BodyType.Json: case BodyType.Json:
var formatting = responseMessage.BodyData.BodyAsJsonIndented == true var formatting = responseMessage.BodyData.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None;
? Formatting.Indented var jsonBody = JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson, new JsonSerializerSettings { Formatting = formatting, NullValueHandling = NullValueHandling.Ignore });
: Formatting.None;
string jsonBody = JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson, new JsonSerializerSettings { Formatting = formatting, NullValueHandling = NullValueHandling.Ignore });
return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(jsonBody); return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(jsonBody);
case BodyType.Bytes: case BodyType.Bytes:
+25 -3
View File
@@ -35,15 +35,32 @@ internal class MappingMatcher : IMappingMatcher
{ {
var nextState = GetNextState(mapping); var nextState = GetNextState(mapping);
possibleMappings.Add(new MappingMatcherResult var mappingMatcherResult = new MappingMatcherResult
{ {
Mapping = mapping, Mapping = mapping,
RequestMatchResult = mapping.GetRequestMatchResult(request, nextState) RequestMatchResult = mapping.GetRequestMatchResult(request, nextState)
}); };
var exceptions = mappingMatcherResult.RequestMatchResult.MatchDetails
.Where(md => md.Exception != null)
.Select(md => md.Exception)
.ToArray();
if (!exceptions.Any())
{
possibleMappings.Add(mappingMatcherResult);
}
else if (!request.AbsolutePath.StartsWith("/__admin", StringComparison.OrdinalIgnoreCase))
{
foreach (var ex in exceptions)
{
LogException(mapping, ex!);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
_options.Logger.Error($"Getting a Request MatchResult for Mapping '{mapping.Guid}' failed. This mapping will not be evaluated. Exception: {ex}"); LogException(mapping, ex);
} }
} }
@@ -66,6 +83,11 @@ internal class MappingMatcher : IMappingMatcher
return (match, partialMatch); return (match, partialMatch);
} }
private void LogException(IMapping mapping, Exception ex)
{
_options.Logger.Error($"Getting a Request MatchResult for Mapping '{mapping.Guid}' failed. This mapping will not be evaluated. Exception: {ex}");
}
private string? GetNextState(IMapping mapping) private string? GetNextState(IMapping mapping)
{ {
// If the mapping does not have a scenario or _options.Scenarios does not contain this scenario from the mapping, // If the mapping does not have a scenario or _options.Scenarios does not contain this scenario from the mapping,
+19 -7
View File
@@ -12,6 +12,8 @@ using WireMock.Types;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Settings; using WireMock.Settings;
using System.Collections.Generic; using System.Collections.Generic;
using WireMock.Constants;
using WireMock.Util;
#if !USE_ASPNETCORE #if !USE_ASPNETCORE
using IContext = Microsoft.Owin.IOwinContext; using IContext = Microsoft.Owin.IOwinContext;
using OwinMiddleware = Microsoft.Owin.OwinMiddleware; using OwinMiddleware = Microsoft.Owin.OwinMiddleware;
@@ -105,7 +107,7 @@ namespace WireMock.Owin
{ {
logRequest = true; logRequest = true;
_options.Logger.Warn("HttpStatusCode set to 404 : No matching mapping found"); _options.Logger.Warn("HttpStatusCode set to 404 : No matching mapping found");
response = ResponseMessageBuilder.Create("No matching mapping found", 404); response = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
return; return;
} }
@@ -113,11 +115,11 @@ namespace WireMock.Owin
if (targetMapping.IsAdminInterface && _options.AuthenticationMatcher != null && request.Headers != null) if (targetMapping.IsAdminInterface && _options.AuthenticationMatcher != null && request.Headers != null)
{ {
bool present = request.Headers.TryGetValue(HttpKnownHeaderNames.Authorization, out WireMockList<string> authorization); bool present = request.Headers.TryGetValue(HttpKnownHeaderNames.Authorization, out WireMockList<string>? authorization);
if (!present || _options.AuthenticationMatcher.IsMatch(authorization!.ToString()) < MatchScores.Perfect) if (!present || _options.AuthenticationMatcher.IsMatch(authorization!.ToString()).Score < MatchScores.Perfect)
{ {
_options.Logger.Error("HttpStatusCode set to 401"); _options.Logger.Error("HttpStatusCode set to 401");
response = ResponseMessageBuilder.Create(null, HttpStatusCode.Unauthorized); response = ResponseMessageBuilder.Create(HttpStatusCode.Unauthorized, null);
return; return;
} }
} }
@@ -161,8 +163,8 @@ namespace WireMock.Owin
} }
catch (Exception ex) catch (Exception ex)
{ {
_options.Logger.Error($"Providing a Response for Mapping '{result.Match?.Mapping?.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}"); _options.Logger.Error($"Providing a Response for Mapping '{result.Match?.Mapping.Guid}' failed. HttpStatusCode set to 500. Exception: {ex}");
response = ResponseMessageBuilder.Create(ex.Message, 500); response = ResponseMessageBuilder.Create(500, ex.Message);
} }
finally finally
{ {
@@ -196,7 +198,17 @@ namespace WireMock.Owin
// Empty catch // Empty catch
} }
await _responseMapper.MapAsync(response, ctx.Response).ConfigureAwait(false); try
{
await _responseMapper.MapAsync(response, ctx.Response).ConfigureAwait(false);
}
catch (Exception ex)
{
_options.Logger.Error("HttpStatusCode set to 404 : No matching mapping found", ex);
var notFoundResponse = ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound);
await _responseMapper.MapAsync(notFoundResponse, ctx.Response).ConfigureAwait(false);
}
} }
await CompletedTask.ConfigureAwait(false); await CompletedTask.ConfigureAwait(false);
+15 -11
View File
@@ -177,25 +177,29 @@ public class RequestMessage : IRequestMessage
DetectedBodyTypeFromContentType = BodyData?.DetectedBodyTypeFromContentType.ToString(); DetectedBodyTypeFromContentType = BodyData?.DetectedBodyTypeFromContentType.ToString();
DetectedCompression = BodyData?.DetectedCompression; DetectedCompression = BodyData?.DetectedCompression;
#if MIMEKIT
try
{
BodyAsMimeMessage = MimeKitUtils.GetMimeMessage(BodyData, headers![HttpKnownHeaderNames.ContentType].First());
}
catch
{
// Ignore exception from MimeMessage.Load
}
#endif
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value)); Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
Cookies = cookies; Cookies = cookies;
RawQuery = urlDetails.Url.Query; RawQuery = urlDetails.Url.Query;
Query = QueryStringParser.Parse(RawQuery, options?.QueryParameterMultipleValueSupport); Query = QueryStringParser.Parse(RawQuery, options?.QueryParameterMultipleValueSupport);
QueryIgnoreCase = new Dictionary<string, WireMockList<string>>(Query, StringComparer.OrdinalIgnoreCase); QueryIgnoreCase = new Dictionary<string, WireMockList<string>>(Query, StringComparer.OrdinalIgnoreCase);
#if USE_ASPNETCORE #if USE_ASPNETCORE
ClientCertificate = clientCertificate; ClientCertificate = clientCertificate;
#endif #endif
#if MIMEKIT
try
{
if (MimeKitUtils.TryGetMimeMessage(this, out var mimeMessage))
{
BodyAsMimeMessage = mimeMessage;
}
}
catch
{
// Ignore exception from MimeMessage.Load
}
#endif
} }
/// <inheritdoc /> /// <inheritdoc />
+12 -6
View File
@@ -16,12 +16,17 @@ internal static class ResponseMessageBuilder
{ HttpKnownHeaderNames.ContentType, new WireMockList<string> { WireMockConstants.ContentTypeJson } } { HttpKnownHeaderNames.ContentType, new WireMockList<string> { WireMockConstants.ContentTypeJson } }
}; };
internal static ResponseMessage Create(string? message, HttpStatusCode statusCode, Guid? guid = null) internal static ResponseMessage Create(HttpStatusCode statusCode, string? status, Guid? guid = null)
{ {
return Create(message, (int)statusCode, guid); return Create((int)statusCode, status, guid);
} }
internal static ResponseMessage Create(string? message, int statusCode = 200, Guid? guid = null) internal static ResponseMessage Create(int statusCode, string? status, Guid? guid = null)
{
return Create(statusCode, status, null, guid);
}
internal static ResponseMessage Create(int statusCode, string? status, string? error, Guid? guid = null)
{ {
var response = new ResponseMessage var response = new ResponseMessage
{ {
@@ -29,7 +34,7 @@ internal static class ResponseMessageBuilder
Headers = ContentTypeJsonHeaders Headers = ContentTypeJsonHeaders
}; };
if (message != null) if (status != null || error != null)
{ {
response.BodyData = new BodyData response.BodyData = new BodyData
{ {
@@ -37,7 +42,8 @@ internal static class ResponseMessageBuilder
BodyAsJson = new StatusModel BodyAsJson = new StatusModel
{ {
Guid = guid, Guid = guid,
Status = message Status = status,
Error = error
} }
}; };
} }
@@ -45,7 +51,7 @@ internal static class ResponseMessageBuilder
return response; return response;
} }
internal static ResponseMessage Create(int statusCode) internal static ResponseMessage Create(HttpStatusCode statusCode)
{ {
return new ResponseMessage return new ResponseMessage
{ {
@@ -139,7 +139,6 @@ internal class MappingConverter
sb.AppendLine(@$" .WithBody(new JsonPartialMatcher( sb.AppendLine(@$" .WithBody(new JsonPartialMatcher(
value: {ToCSharpStringLiteral(jsonPartialMatcher.Value.ToString())}, value: {ToCSharpStringLiteral(jsonPartialMatcher.Value.ToString())},
ignoreCase: {ToCSharpBooleanLiteral(jsonPartialMatcher.IgnoreCase)}, ignoreCase: {ToCSharpBooleanLiteral(jsonPartialMatcher.IgnoreCase)},
throwException: {ToCSharpBooleanLiteral(jsonPartialMatcher.ThrowException)},
regex: {ToCSharpBooleanLiteral(jsonPartialMatcher.Regex)} regex: {ToCSharpBooleanLiteral(jsonPartialMatcher.Regex)}
))"); ))");
} }
@@ -148,7 +147,6 @@ internal class MappingConverter
sb.AppendLine(@$" .WithBody(new JsonPartialWildcardMatcher( sb.AppendLine(@$" .WithBody(new JsonPartialWildcardMatcher(
value: {ToCSharpStringLiteral(jsonPartialWildcardMatcher.Value.ToString())}, value: {ToCSharpStringLiteral(jsonPartialWildcardMatcher.Value.ToString())},
ignoreCase: {ToCSharpBooleanLiteral(jsonPartialWildcardMatcher.IgnoreCase)}, ignoreCase: {ToCSharpBooleanLiteral(jsonPartialWildcardMatcher.IgnoreCase)},
throwException: {ToCSharpBooleanLiteral(jsonPartialWildcardMatcher.ThrowException)},
regex: {ToCSharpBooleanLiteral(jsonPartialWildcardMatcher.Regex)} regex: {ToCSharpBooleanLiteral(jsonPartialWildcardMatcher.Regex)}
))"); ))");
} }
+19 -20
View File
@@ -46,7 +46,6 @@ internal class MatcherMapper
var matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch; var matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch;
var matchOperator = StringUtils.ParseMatchOperator(matcher.MatchOperator); var matchOperator = StringUtils.ParseMatchOperator(matcher.MatchOperator);
bool ignoreCase = matcher.IgnoreCase == true; bool ignoreCase = matcher.IgnoreCase == true;
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
bool useRegexExtended = _settings.UseRegexExtended == true; bool useRegexExtended = _settings.UseRegexExtended == true;
bool useRegex = matcher.Regex == true; bool useRegex = matcher.Regex == true;
@@ -64,51 +63,51 @@ internal class MatcherMapper
throw new NotSupportedException("It's not allowed to use the 'CSharpCodeMatcher' because WireMockServerSettings.AllowCSharpCodeMatcher is not set to 'true'."); throw new NotSupportedException("It's not allowed to use the 'CSharpCodeMatcher' because WireMockServerSettings.AllowCSharpCodeMatcher is not set to 'true'.");
case nameof(LinqMatcher): case nameof(LinqMatcher):
return new LinqMatcher(matchBehaviour, throwExceptionWhenMatcherFails, matchOperator, stringPatterns); return new LinqMatcher(matchBehaviour, matchOperator, stringPatterns);
case nameof(ExactMatcher): case nameof(ExactMatcher):
return new ExactMatcher(matchBehaviour, ignoreCase, throwExceptionWhenMatcherFails, matchOperator, stringPatterns); return new ExactMatcher(matchBehaviour, ignoreCase, matchOperator, stringPatterns);
case nameof(ExactObjectMatcher): case nameof(ExactObjectMatcher):
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0], throwExceptionWhenMatcherFails); return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0]);
#if GRAPHQL #if GRAPHQL
case nameof(GraphQLMatcher): case nameof(GraphQLMatcher):
return new GraphQLMatcher(stringPatterns[0].GetPattern(), matchBehaviour, throwExceptionWhenMatcherFails, matchOperator); return new GraphQLMatcher(stringPatterns[0].GetPattern(), matchBehaviour, matchOperator);
#endif #endif
#if MIMEKIT #if MIMEKIT
case nameof(MimePartMatcher): case nameof(MimePartMatcher):
return CreateMimePartMatcher(matchBehaviour, matcher, throwExceptionWhenMatcherFails); return CreateMimePartMatcher(matchBehaviour, matcher);
#endif #endif
case nameof(RegexMatcher): case nameof(RegexMatcher):
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails, useRegexExtended, matchOperator); return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, useRegexExtended, matchOperator);
case nameof(JsonMatcher): case nameof(JsonMatcher):
var valueForJsonMatcher = matcher.Pattern ?? matcher.Patterns; var valueForJsonMatcher = matcher.Pattern ?? matcher.Patterns;
return new JsonMatcher(matchBehaviour, valueForJsonMatcher!, ignoreCase, throwExceptionWhenMatcherFails); return new JsonMatcher(matchBehaviour, valueForJsonMatcher!, ignoreCase);
case nameof(JsonPartialMatcher): case nameof(JsonPartialMatcher):
var valueForJsonPartialMatcher = matcher.Pattern ?? matcher.Patterns; var valueForJsonPartialMatcher = matcher.Pattern ?? matcher.Patterns;
return new JsonPartialMatcher(matchBehaviour, valueForJsonPartialMatcher!, ignoreCase, throwExceptionWhenMatcherFails, useRegex); return new JsonPartialMatcher(matchBehaviour, valueForJsonPartialMatcher!, ignoreCase, useRegex);
case nameof(JsonPartialWildcardMatcher): case nameof(JsonPartialWildcardMatcher):
var valueForJsonPartialWildcardMatcher = matcher.Pattern ?? matcher.Patterns; var valueForJsonPartialWildcardMatcher = matcher.Pattern ?? matcher.Patterns;
return new JsonPartialWildcardMatcher(matchBehaviour, valueForJsonPartialWildcardMatcher!, ignoreCase, throwExceptionWhenMatcherFails, useRegex); return new JsonPartialWildcardMatcher(matchBehaviour, valueForJsonPartialWildcardMatcher!, ignoreCase, useRegex);
case nameof(JsonPathMatcher): case nameof(JsonPathMatcher):
return new JsonPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, matchOperator, stringPatterns); return new JsonPathMatcher(matchBehaviour, matchOperator, stringPatterns);
case nameof(JmesPathMatcher): case nameof(JmesPathMatcher):
return new JmesPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, matchOperator, stringPatterns); return new JmesPathMatcher(matchBehaviour, matchOperator, stringPatterns);
case nameof(XPathMatcher): case nameof(XPathMatcher):
return new XPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, matchOperator, stringPatterns); return new XPathMatcher(matchBehaviour, matchOperator, stringPatterns);
case nameof(WildcardMatcher): case nameof(WildcardMatcher):
return new WildcardMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails, matchOperator); return new WildcardMatcher(matchBehaviour, stringPatterns, ignoreCase, matchOperator);
case nameof(ContentTypeMatcher): case nameof(ContentTypeMatcher):
return new ContentTypeMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails); return new ContentTypeMatcher(matchBehaviour, stringPatterns, ignoreCase);
case nameof(SimMetricsMatcher): case nameof(SimMetricsMatcher):
SimMetricType type = SimMetricType.Levenstein; SimMetricType type = SimMetricType.Levenstein;
@@ -117,7 +116,7 @@ internal class MatcherMapper
throw new NotSupportedException($"Matcher '{matcherName}' with Type '{matcherType}' is not supported."); throw new NotSupportedException($"Matcher '{matcherName}' with Type '{matcherType}' is not supported.");
} }
return new SimMetricsMatcher(matchBehaviour, stringPatterns, type, throwExceptionWhenMatcherFails); return new SimMetricsMatcher(matchBehaviour, stringPatterns, type);
default: default:
if (_settings.CustomMatcherMappings != null && _settings.CustomMatcherMappings.ContainsKey(matcherName)) if (_settings.CustomMatcherMappings != null && _settings.CustomMatcherMappings.ContainsKey(matcherName))
@@ -236,7 +235,7 @@ internal class MatcherMapper
return EmptyArray<AnyOf<string, StringPattern>>.Value; return EmptyArray<AnyOf<string, StringPattern>>.Value;
} }
private static ExactObjectMatcher CreateExactObjectMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> stringPattern, bool throwException) private static ExactObjectMatcher CreateExactObjectMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> stringPattern)
{ {
byte[] bytePattern; byte[] bytePattern;
try try
@@ -248,18 +247,18 @@ internal class MatcherMapper
throw new ArgumentException($"Matcher 'ExactObjectMatcher' has invalid pattern. The pattern value '{stringPattern}' is not a Base64String.", nameof(stringPattern)); throw new ArgumentException($"Matcher 'ExactObjectMatcher' has invalid pattern. The pattern value '{stringPattern}' is not a Base64String.", nameof(stringPattern));
} }
return new ExactObjectMatcher(matchBehaviour, bytePattern, throwException); return new ExactObjectMatcher(matchBehaviour, bytePattern);
} }
#if MIMEKIT #if MIMEKIT
private MimePartMatcher CreateMimePartMatcher(MatchBehaviour matchBehaviour, MatcherModel? matcher, bool throwExceptionWhenMatcherFails) private MimePartMatcher CreateMimePartMatcher(MatchBehaviour matchBehaviour, MatcherModel? matcher)
{ {
var contentTypeMatcher = Map(matcher?.ContentTypeMatcher) as IStringMatcher; var contentTypeMatcher = Map(matcher?.ContentTypeMatcher) as IStringMatcher;
var contentDispositionMatcher = Map(matcher?.ContentDispositionMatcher) as IStringMatcher; var contentDispositionMatcher = Map(matcher?.ContentDispositionMatcher) as IStringMatcher;
var contentTransferEncodingMatcher = Map(matcher?.ContentTransferEncodingMatcher) as IStringMatcher; var contentTransferEncodingMatcher = Map(matcher?.ContentTransferEncodingMatcher) as IStringMatcher;
var contentMatcher = Map(matcher?.ContentMatcher); var contentMatcher = Map(matcher?.ContentMatcher);
return new MimePartMatcher(matchBehaviour, contentTypeMatcher, contentDispositionMatcher, contentTransferEncodingMatcher, contentMatcher, throwExceptionWhenMatcherFails); return new MimePartMatcher(matchBehaviour, contentTypeMatcher, contentDispositionMatcher, contentTransferEncodingMatcher, contentMatcher);
} }
#endif #endif
} }
@@ -30,8 +30,8 @@ internal class ProxyMappingConverter
{ {
var useDefinedRequestMatchers = proxyAndRecordSettings.UseDefinedRequestMatchers; var useDefinedRequestMatchers = proxyAndRecordSettings.UseDefinedRequestMatchers;
var excludedHeaders = new List<string>(proxyAndRecordSettings.ExcludedHeaders ?? new string[] { }) { "Cookie" }; var excludedHeaders = new List<string>(proxyAndRecordSettings.ExcludedHeaders ?? new string[] { }) { "Cookie" };
var excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? new string[0]; var excludedCookies = proxyAndRecordSettings.ExcludedCookies ?? EmptyArray<string>.Value;
var excludedParams = proxyAndRecordSettings.ExcludedParams ?? new string[0]; var excludedParams = proxyAndRecordSettings.ExcludedParams ?? EmptyArray<string>.Value;
var request = (Request?)mapping?.RequestMatcher; var request = (Request?)mapping?.RequestMatcher;
var clientIPMatcher = request?.GetRequestMessageMatcher<RequestMessageClientIPMatcher>(); var clientIPMatcher = request?.GetRequestMessageMatcher<RequestMessageClientIPMatcher>();
@@ -137,7 +137,6 @@ internal class ProxyMappingConverter
} }
// Body // Body
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
if (useDefinedRequestMatchers && bodyMatcher?.Matchers is not null) if (useDefinedRequestMatchers && bodyMatcher?.Matchers is not null)
{ {
newRequest.WithBody(bodyMatcher.Matchers); newRequest.WithBody(bodyMatcher.Matchers);
@@ -147,16 +146,16 @@ internal class ProxyMappingConverter
switch (requestMessage.BodyData?.DetectedBodyType) switch (requestMessage.BodyData?.DetectedBodyType)
{ {
case BodyType.Json: case BodyType.Json:
newRequest.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson!, true, throwExceptionWhenMatcherFails)); newRequest.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson!, true));
break; break;
case BodyType.String: case BodyType.String:
case BodyType.FormUrlEncoded: case BodyType.FormUrlEncoded:
newRequest.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, true, throwExceptionWhenMatcherFails, MatchOperator.Or, requestMessage.BodyData.BodyAsString!)); newRequest.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, true, MatchOperator.Or, requestMessage.BodyData.BodyAsString!));
break; break;
case BodyType.Bytes: case BodyType.Bytes:
newRequest.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes!, throwExceptionWhenMatcherFails)); newRequest.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes!));
break; break;
} }
} }
+24 -26
View File
@@ -237,7 +237,6 @@ public partial class WireMockServer
ReadStaticMappings = _settings.ReadStaticMappings, ReadStaticMappings = _settings.ReadStaticMappings,
RequestLogExpirationDuration = _settings.RequestLogExpirationDuration, RequestLogExpirationDuration = _settings.RequestLogExpirationDuration,
SaveUnmatchedRequests = _settings.SaveUnmatchedRequests, SaveUnmatchedRequests = _settings.SaveUnmatchedRequests,
ThrowExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails,
UseRegexExtended = _settings.UseRegexExtended, UseRegexExtended = _settings.UseRegexExtended,
WatchStaticMappings = _settings.WatchStaticMappings, WatchStaticMappings = _settings.WatchStaticMappings,
WatchStaticMappingsInSubdirectories = _settings.WatchStaticMappingsInSubdirectories, WatchStaticMappingsInSubdirectories = _settings.WatchStaticMappingsInSubdirectories,
@@ -273,7 +272,6 @@ public partial class WireMockServer
_settings.ReadStaticMappings = settings.ReadStaticMappings; _settings.ReadStaticMappings = settings.ReadStaticMappings;
_settings.RequestLogExpirationDuration = settings.RequestLogExpirationDuration; _settings.RequestLogExpirationDuration = settings.RequestLogExpirationDuration;
_settings.SaveUnmatchedRequests = settings.SaveUnmatchedRequests; _settings.SaveUnmatchedRequests = settings.SaveUnmatchedRequests;
_settings.ThrowExceptionWhenMatcherFails = settings.ThrowExceptionWhenMatcherFails;
_settings.UseRegexExtended = settings.UseRegexExtended; _settings.UseRegexExtended = settings.UseRegexExtended;
_settings.WatchStaticMappings = settings.WatchStaticMappings; _settings.WatchStaticMappings = settings.WatchStaticMappings;
_settings.WatchStaticMappingsInSubdirectories = settings.WatchStaticMappingsInSubdirectories; _settings.WatchStaticMappingsInSubdirectories = settings.WatchStaticMappingsInSubdirectories;
@@ -303,7 +301,7 @@ public partial class WireMockServer
_options.AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate; _options.AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate;
#endif #endif
return ResponseMessageBuilder.Create("Settings updated"); return ResponseMessageBuilder.Create(200, "Settings updated");
} }
#endregion Settings #endregion Settings
@@ -314,7 +312,7 @@ public partial class WireMockServer
if (mapping == null) if (mapping == null)
{ {
_settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found");
return ResponseMessageBuilder.Create("Mapping not found", HttpStatusCode.NotFound); return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found");
} }
var model = _mappingConverter.ToMappingModel(mapping); var model = _mappingConverter.ToMappingModel(mapping);
@@ -330,14 +328,14 @@ public partial class WireMockServer
if (code is null) if (code is null)
{ {
_settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found");
return ResponseMessageBuilder.Create("Mapping not found", HttpStatusCode.NotFound); return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found");
} }
return ToResponseMessage(code); return ToResponseMessage(code);
} }
_settings.Logger.Warn("HttpStatusCode set to 400"); _settings.Logger.Warn("HttpStatusCode set to 400");
return ResponseMessageBuilder.Create("GUID is missing", HttpStatusCode.BadRequest); return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "GUID is missing");
} }
private static MappingConverterType GetMappingConverterType(IRequestMessage requestMessage) private static MappingConverterType GetMappingConverterType(IRequestMessage requestMessage)
@@ -365,22 +363,22 @@ public partial class WireMockServer
var mappingModel = DeserializeObject<MappingModel>(requestMessage); var mappingModel = DeserializeObject<MappingModel>(requestMessage);
var guidFromPut = ConvertMappingAndRegisterAsRespondProvider(mappingModel, guid); var guidFromPut = ConvertMappingAndRegisterAsRespondProvider(mappingModel, guid);
return ResponseMessageBuilder.Create("Mapping added or updated", HttpStatusCode.OK, guidFromPut); return ResponseMessageBuilder.Create(HttpStatusCode.OK, "Mapping added or updated", guidFromPut);
} }
_settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found");
return ResponseMessageBuilder.Create("Mapping not found", HttpStatusCode.NotFound); return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found");
} }
private IResponseMessage MappingDelete(IRequestMessage requestMessage) private IResponseMessage MappingDelete(IRequestMessage requestMessage)
{ {
if (TryParseGuidFromRequestMessage(requestMessage, out var guid) && DeleteMapping(guid)) if (TryParseGuidFromRequestMessage(requestMessage, out var guid) && DeleteMapping(guid))
{ {
return ResponseMessageBuilder.Create("Mapping removed", HttpStatusCode.OK, guid); return ResponseMessageBuilder.Create(HttpStatusCode.OK, "Mapping removed", guid);
} }
_settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found"); _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found");
return ResponseMessageBuilder.Create("Mapping not found", HttpStatusCode.NotFound); return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Mapping not found");
} }
private static bool TryParseGuidFromRequestMessage(IRequestMessage requestMessage, out Guid guid) private static bool TryParseGuidFromRequestMessage(IRequestMessage requestMessage, out Guid guid)
@@ -409,7 +407,7 @@ public partial class WireMockServer
{ {
SaveStaticMappings(); SaveStaticMappings();
return ResponseMessageBuilder.Create("Mappings saved to disk"); return ResponseMessageBuilder.Create(200, "Mappings saved to disk");
} }
private MappingModel[] ToMappingModels() private MappingModel[] ToMappingModels()
@@ -439,22 +437,22 @@ public partial class WireMockServer
if (mappingModels.Length == 1) if (mappingModels.Length == 1)
{ {
Guid? guid = ConvertMappingAndRegisterAsRespondProvider(mappingModels[0]); Guid? guid = ConvertMappingAndRegisterAsRespondProvider(mappingModels[0]);
return ResponseMessageBuilder.Create("Mapping added", 201, guid); return ResponseMessageBuilder.Create(201, "Mapping added", guid);
} }
ConvertMappingsAndRegisterAsRespondProvider(mappingModels); ConvertMappingsAndRegisterAsRespondProvider(mappingModels);
return ResponseMessageBuilder.Create("Mappings added", 201); return ResponseMessageBuilder.Create(201, "Mappings added");
} }
catch (ArgumentException a) catch (ArgumentException a)
{ {
_settings.Logger.Error("HttpStatusCode set to 400 {0}", a); _settings.Logger.Error("HttpStatusCode set to 400 {0}", a);
return ResponseMessageBuilder.Create(a.Message, 400); return ResponseMessageBuilder.Create(400, a.Message);
} }
catch (Exception e) catch (Exception e)
{ {
_settings.Logger.Error("HttpStatusCode set to 500 {0}", e); _settings.Logger.Error("HttpStatusCode set to 500 {0}", e);
return ResponseMessageBuilder.Create(e.ToString(), 500); return ResponseMessageBuilder.Create(500, e.ToString());
} }
} }
@@ -465,18 +463,18 @@ public partial class WireMockServer
var deletedGuids = MappingsDeleteMappingFromBody(requestMessage); var deletedGuids = MappingsDeleteMappingFromBody(requestMessage);
if (deletedGuids != null) if (deletedGuids != null)
{ {
return ResponseMessageBuilder.Create($"Mappings deleted. Affected GUIDs: [{string.Join(", ", deletedGuids.ToArray())}]"); return ResponseMessageBuilder.Create(200, $"Mappings deleted. Affected GUIDs: [{string.Join(", ", deletedGuids.ToArray())}]");
} }
// return bad request // return bad request
return ResponseMessageBuilder.Create("Poorly formed mapping JSON.", 400); return ResponseMessageBuilder.Create(400, "Poorly formed mapping JSON.");
} }
ResetMappings(); ResetMappings();
ResetScenarios(); ResetScenarios();
return ResponseMessageBuilder.Create("Mappings deleted"); return ResponseMessageBuilder.Create(200, "Mappings deleted");
} }
private IEnumerable<Guid>? MappingsDeleteMappingFromBody(IRequestMessage requestMessage) private IEnumerable<Guid>? MappingsDeleteMappingFromBody(IRequestMessage requestMessage)
@@ -528,7 +526,7 @@ public partial class WireMockServer
message = $"{message} and static mappings reloaded"; message = $"{message} and static mappings reloaded";
} }
return ResponseMessageBuilder.Create(message); return ResponseMessageBuilder.Create(200, message);
} }
#endregion Mappings #endregion Mappings
@@ -546,18 +544,18 @@ public partial class WireMockServer
} }
_settings.Logger.Warn("HttpStatusCode set to 404 : Request not found"); _settings.Logger.Warn("HttpStatusCode set to 404 : Request not found");
return ResponseMessageBuilder.Create("Request not found", HttpStatusCode.NotFound); return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Request not found");
} }
private IResponseMessage RequestDelete(IRequestMessage requestMessage) private IResponseMessage RequestDelete(IRequestMessage requestMessage)
{ {
if (TryParseGuidFromRequestMessage(requestMessage, out var guid) && DeleteLogEntry(guid)) if (TryParseGuidFromRequestMessage(requestMessage, out var guid) && DeleteLogEntry(guid))
{ {
return ResponseMessageBuilder.Create("Request removed"); return ResponseMessageBuilder.Create(200, "Request removed");
} }
_settings.Logger.Warn("HttpStatusCode set to 404 : Request not found"); _settings.Logger.Warn("HttpStatusCode set to 404 : Request not found");
return ResponseMessageBuilder.Create("Request not found", HttpStatusCode.NotFound); return ResponseMessageBuilder.Create(HttpStatusCode.NotFound, "Request not found");
} }
#endregion Request/{guid} #endregion Request/{guid}
@@ -576,7 +574,7 @@ public partial class WireMockServer
{ {
ResetLogEntries(); ResetLogEntries();
return ResponseMessageBuilder.Create("Requests deleted"); return ResponseMessageBuilder.Create(200, "Requests deleted");
} }
#endregion Requests #endregion Requests
@@ -623,7 +621,7 @@ public partial class WireMockServer
{ {
ResetScenarios(); ResetScenarios();
return ResponseMessageBuilder.Create("Scenarios reset"); return ResponseMessageBuilder.Create(200, "Scenarios reset");
} }
private IResponseMessage ScenarioReset(IRequestMessage requestMessage) private IResponseMessage ScenarioReset(IRequestMessage requestMessage)
@@ -633,8 +631,8 @@ public partial class WireMockServer
requestMessage.Path.Split('/').Reverse().Skip(1).First(); requestMessage.Path.Split('/').Reverse().Skip(1).First();
return ResetScenario(name) ? return ResetScenario(name) ?
ResponseMessageBuilder.Create("Scenario reset") : ResponseMessageBuilder.Create(200, "Scenario reset") :
ResponseMessageBuilder.Create($"No scenario found by name '{name}'.", HttpStatusCode.NotFound); ResponseMessageBuilder.Create(HttpStatusCode.NotFound, $"No scenario found by name '{name}'.");
} }
#endregion #endregion
@@ -1,5 +1,6 @@
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Text; using System.Text;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Types; using WireMock.Types;
@@ -25,7 +26,7 @@ namespace WireMock.Server
_settings.FileSystemHandler.WriteFile(filename, requestMessage.BodyAsBytes); _settings.FileSystemHandler.WriteFile(filename, requestMessage.BodyAsBytes);
return ResponseMessageBuilder.Create("File created"); return ResponseMessageBuilder.Create(200, "File created");
} }
private IResponseMessage FilePut(IRequestMessage requestMessage) private IResponseMessage FilePut(IRequestMessage requestMessage)
@@ -35,12 +36,12 @@ namespace WireMock.Server
if (!_settings.FileSystemHandler.FileExists(filename)) if (!_settings.FileSystemHandler.FileExists(filename))
{ {
_settings.Logger.Info("The file '{0}' does not exist, updating file will be skipped.", filename); _settings.Logger.Info("The file '{0}' does not exist, updating file will be skipped.", filename);
return ResponseMessageBuilder.Create("File is not found", 404); return ResponseMessageBuilder.Create(404, "File is not found");
} }
_settings.FileSystemHandler.WriteFile(filename, requestMessage.BodyAsBytes); _settings.FileSystemHandler.WriteFile(filename, requestMessage.BodyAsBytes);
return ResponseMessageBuilder.Create("File updated"); return ResponseMessageBuilder.Create(200, "File updated");
} }
private IResponseMessage FileGet(IRequestMessage requestMessage) private IResponseMessage FileGet(IRequestMessage requestMessage)
@@ -50,7 +51,7 @@ namespace WireMock.Server
if (!_settings.FileSystemHandler.FileExists(filename)) if (!_settings.FileSystemHandler.FileExists(filename))
{ {
_settings.Logger.Info("The file '{0}' does not exist.", filename); _settings.Logger.Info("The file '{0}' does not exist.", filename);
return ResponseMessageBuilder.Create("File is not found", 404); return ResponseMessageBuilder.Create(404, "File is not found");
} }
byte[] bytes = _settings.FileSystemHandler.ReadFile(filename); byte[] bytes = _settings.FileSystemHandler.ReadFile(filename);
@@ -86,10 +87,10 @@ namespace WireMock.Server
if (!_settings.FileSystemHandler.FileExists(filename)) if (!_settings.FileSystemHandler.FileExists(filename))
{ {
_settings.Logger.Info("The file '{0}' does not exist.", filename); _settings.Logger.Info("The file '{0}' does not exist.", filename);
return ResponseMessageBuilder.Create(404); return ResponseMessageBuilder.Create(HttpStatusCode.NotFound);
} }
return ResponseMessageBuilder.Create(204); return ResponseMessageBuilder.Create(HttpStatusCode.NoContent);
} }
private IResponseMessage FileDelete(IRequestMessage requestMessage) private IResponseMessage FileDelete(IRequestMessage requestMessage)
@@ -99,11 +100,11 @@ namespace WireMock.Server
if (!_settings.FileSystemHandler.FileExists(filename)) if (!_settings.FileSystemHandler.FileExists(filename))
{ {
_settings.Logger.Info("The file '{0}' does not exist.", filename); _settings.Logger.Info("The file '{0}' does not exist.", filename);
return ResponseMessageBuilder.Create("File is not deleted", 404); return ResponseMessageBuilder.Create(404, "File is not deleted");
} }
_settings.FileSystemHandler.DeleteFile(filename); _settings.FileSystemHandler.DeleteFile(filename);
return ResponseMessageBuilder.Create("File deleted."); return ResponseMessageBuilder.Create(200, "File deleted.");
} }
private string GetFileNameFromRequestMessage(IRequestMessage requestMessage) private string GetFileNameFromRequestMessage(IRequestMessage requestMessage)
@@ -52,7 +52,7 @@ public partial class WireMockServer
if (mappingModels.Length == 1) if (mappingModels.Length == 1)
{ {
Guid? guid = ConvertWireMockOrgMappingAndRegisterAsRespondProvider(mappingModels[0]); Guid? guid = ConvertWireMockOrgMappingAndRegisterAsRespondProvider(mappingModels[0]);
return ResponseMessageBuilder.Create("Mapping added", 201, guid); return ResponseMessageBuilder.Create(201, "Mapping added", guid);
} }
foreach (var mappingModel in mappingModels) foreach (var mappingModel in mappingModels)
@@ -60,17 +60,17 @@ public partial class WireMockServer
ConvertWireMockOrgMappingAndRegisterAsRespondProvider(mappingModel); ConvertWireMockOrgMappingAndRegisterAsRespondProvider(mappingModel);
} }
return ResponseMessageBuilder.Create("Mappings added", 201); return ResponseMessageBuilder.Create(201, "Mappings added");
} }
catch (ArgumentException a) catch (ArgumentException a)
{ {
_settings.Logger.Error("HttpStatusCode set to 400 {0}", a); _settings.Logger.Error("HttpStatusCode set to 400 {0}", a);
return ResponseMessageBuilder.Create(a.Message, 400); return ResponseMessageBuilder.Create(400, a.Message);
} }
catch (Exception e) catch (Exception e)
{ {
_settings.Logger.Error("HttpStatusCode set to 500 {0}", e); _settings.Logger.Error("HttpStatusCode set to 500 {0}", e);
return ResponseMessageBuilder.Create(e.ToString(), 500); return ResponseMessageBuilder.Create(500, e.ToString());
} }
} }
@@ -1,7 +1,7 @@
using System.Net;
#if OPENAPIPARSER #if OPENAPIPARSER
using System; using System;
using System.Linq; using System.Linq;
using System.Net;
using WireMock.Net.OpenApiParser; using WireMock.Net.OpenApiParser;
#endif #endif
@@ -14,16 +14,16 @@ public partial class WireMockServer
#if OPENAPIPARSER #if OPENAPIPARSER
try try
{ {
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic); var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body!, out var diagnostic);
return diagnostic.Errors.Any() ? ToJson(diagnostic, false, HttpStatusCode.BadRequest) : ToJson(mappingModels); return diagnostic.Errors.Any() ? ToJson(diagnostic, false, HttpStatusCode.BadRequest) : ToJson(mappingModels);
} }
catch (Exception e) catch (Exception e)
{ {
_settings.Logger.Error("HttpStatusCode set to {0} {1}", HttpStatusCode.BadRequest, e); _settings.Logger.Error("HttpStatusCode set to {0} {1}", HttpStatusCode.BadRequest, e);
return ResponseMessageBuilder.Create(e.Message, HttpStatusCode.BadRequest); return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, e.Message);
} }
#else #else
return ResponseMessageBuilder.Create("Not supported for .NETStandard 1.3 and .NET 4.5.2 or lower.", 400); return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Not supported for .NETStandard 1.3 and .NET 4.5.2 or lower.");
#endif #endif
} }
@@ -32,7 +32,7 @@ public partial class WireMockServer
#if OPENAPIPARSER #if OPENAPIPARSER
try try
{ {
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic); var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body!, out var diagnostic);
if (diagnostic.Errors.Any()) if (diagnostic.Errors.Any())
{ {
return ToJson(diagnostic, false, HttpStatusCode.BadRequest); return ToJson(diagnostic, false, HttpStatusCode.BadRequest);
@@ -40,15 +40,15 @@ public partial class WireMockServer
ConvertMappingsAndRegisterAsRespondProvider(mappingModels); ConvertMappingsAndRegisterAsRespondProvider(mappingModels);
return ResponseMessageBuilder.Create("OpenApi document converted to Mappings", HttpStatusCode.Created); return ResponseMessageBuilder.Create(HttpStatusCode.Created, "OpenApi document converted to Mappings");
} }
catch (Exception e) catch (Exception e)
{ {
_settings.Logger.Error("HttpStatusCode set to {0} {1}", HttpStatusCode.BadRequest, e); _settings.Logger.Error("HttpStatusCode set to {0} {1}", HttpStatusCode.BadRequest, e);
return ResponseMessageBuilder.Create(e.Message, HttpStatusCode.BadRequest); return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, e.Message);
} }
#else #else
return ResponseMessageBuilder.Create("Not supported for .NETStandard 1.3 and .NET 4.5.2 or lower.", 400); return ResponseMessageBuilder.Create(HttpStatusCode.BadRequest, "Not supported for .NETStandard 1.3 and .NET 4.5.2 or lower.");
#endif #endif
} }
} }
+3 -1
View File
@@ -4,6 +4,7 @@ using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using JetBrains.Annotations; using JetBrains.Annotations;
@@ -11,6 +12,7 @@ using Newtonsoft.Json;
using Stef.Validation; using Stef.Validation;
using WireMock.Admin.Mappings; using WireMock.Admin.Mappings;
using WireMock.Authentication; using WireMock.Authentication;
using WireMock.Constants;
using WireMock.Exceptions; using WireMock.Exceptions;
using WireMock.Handlers; using WireMock.Handlers;
using WireMock.Http; using WireMock.Http;
@@ -391,7 +393,7 @@ public partial class WireMockServer : IWireMockServer
Given(Request.Create().WithPath("/*").UsingAnyMethod()) Given(Request.Create().WithPath("/*").UsingAnyMethod())
.WithGuid(Guid.Parse("90008000-0000-4444-a17e-669cd84f1f05")) .WithGuid(Guid.Parse("90008000-0000-4444-a17e-669cd84f1f05"))
.AtPriority(1000) .AtPriority(1000)
.RespondWith(new DynamicResponseProvider(_ => ResponseMessageBuilder.Create("No matching mapping found", 404))); .RespondWith(new DynamicResponseProvider(_ => ResponseMessageBuilder.Create(HttpStatusCode.NotFound, WireMockConstants.NoMatchingFound)));
} }
/// <inheritdoc cref="IWireMockServer.Reset" /> /// <inheritdoc cref="IWireMockServer.Reset" />
@@ -221,12 +221,6 @@ public class WireMockServerSettings
[PublicAPI] [PublicAPI]
public bool? HandleRequestsSynchronously { get; set; } public bool? HandleRequestsSynchronously { get; set; }
/// <summary>
/// Throw an exception when the <see cref="IMatcher"/> fails because of invalid input. (default set to <c>false</c>).
/// </summary>
[PublicAPI]
public bool? ThrowExceptionWhenMatcherFails { get; set; }
/// <summary> /// <summary>
/// If https is used, these settings can be used to configure the CertificateSettings in case a custom certificate instead the default .NET certificate should be used. /// If https is used, these settings can be used to configure the CertificateSettings in case a custom certificate instead the default .NET certificate should be used.
/// ///
@@ -57,7 +57,6 @@ public static class WireMockServerSettingsParser
SaveUnmatchedRequests = parser.GetBoolValue(nameof(WireMockServerSettings.SaveUnmatchedRequests)), SaveUnmatchedRequests = parser.GetBoolValue(nameof(WireMockServerSettings.SaveUnmatchedRequests)),
StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true), StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true),
StartTimeout = parser.GetIntValue(nameof(WireMockServerSettings.StartTimeout), WireMockServerSettings.DefaultStartTimeout), StartTimeout = parser.GetIntValue(nameof(WireMockServerSettings.StartTimeout), WireMockServerSettings.DefaultStartTimeout),
ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails"),
UseRegexExtended = parser.GetBoolValue(nameof(WireMockServerSettings.UseRegexExtended), true), UseRegexExtended = parser.GetBoolValue(nameof(WireMockServerSettings.UseRegexExtended), true),
WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"), WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"),
WatchStaticMappingsInSubdirectories = parser.GetBoolValue("WatchStaticMappingsInSubdirectories"), WatchStaticMappingsInSubdirectories = parser.GetBoolValue("WatchStaticMappingsInSubdirectories"),
+5 -5
View File
@@ -85,27 +85,27 @@ internal static class BodyParser
public static BodyType DetectBodyTypeFromContentType(string? contentTypeValue) public static BodyType DetectBodyTypeFromContentType(string? contentTypeValue)
{ {
if (string.IsNullOrEmpty(contentTypeValue) || !MediaTypeHeaderValue.TryParse(contentTypeValue, out MediaTypeHeaderValue contentType)) if (string.IsNullOrEmpty(contentTypeValue) || !MediaTypeHeaderValue.TryParse(contentTypeValue, out MediaTypeHeaderValue? contentType))
{ {
return BodyType.Bytes; return BodyType.Bytes;
} }
if (MatchScores.IsPerfect(FormUrlEncodedMatcher.IsMatch(contentType.MediaType))) if (FormUrlEncodedMatcher.IsMatch(contentType.MediaType).IsPerfect())
{ {
return BodyType.FormUrlEncoded; return BodyType.FormUrlEncoded;
} }
if (TextContentTypeMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType)))) if (TextContentTypeMatchers.Any(matcher => matcher.IsMatch(contentType.MediaType).IsPerfect()))
{ {
return BodyType.String; return BodyType.String;
} }
if (JsonContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType)))) if (JsonContentTypesMatchers.Any(matcher => matcher.IsMatch(contentType.MediaType).IsPerfect()))
{ {
return BodyType.Json; return BodyType.Json;
} }
if (MultipartContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType)))) if (MultipartContentTypesMatchers.Any(matcher => matcher.IsMatch(contentType.MediaType).IsPerfect()))
{ {
return BodyType.MultiPart; return BodyType.MultiPart;
} }
+23 -10
View File
@@ -1,8 +1,11 @@
#if MIMEKIT #if MIMEKIT
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using MimeKit; using MimeKit;
using Stef.Validation;
using WireMock.Http; using WireMock.Http;
using WireMock.Types; using WireMock.Types;
@@ -10,21 +13,31 @@ namespace WireMock.Util;
internal static class MimeKitUtils internal static class MimeKitUtils
{ {
public static MimeMessage GetMimeMessage(IBodyData? bodyData, string contentTypeHeaderValue) public static bool TryGetMimeMessage(IRequestMessage requestMessage, [NotNullWhen(true)] out MimeMessage? mimeMessage)
{ {
var bytes = bodyData?.DetectedBodyType switch Guard.NotNull(requestMessage);
if (requestMessage.BodyData != null && requestMessage.Headers?.TryGetValue(HttpKnownHeaderNames.ContentType, out var contentTypeHeader) == true && contentTypeHeader.Any())
{ {
// If the body is bytes, use the BodyAsBytes to match on. var bytes = requestMessage.BodyData?.DetectedBodyType switch
BodyType.Bytes => bodyData.BodyAsBytes!, {
// If the body is bytes, use the BodyAsBytes to match on.
BodyType.Bytes => requestMessage.BodyData.BodyAsBytes!,
// If the body is a String or MultiPart, use the BodyAsString to match on. // If the body is a String or MultiPart, use the BodyAsString to match on.
BodyType.String or BodyType.MultiPart => Encoding.UTF8.GetBytes(bodyData.BodyAsString!), BodyType.String or BodyType.MultiPart => Encoding.UTF8.GetBytes(requestMessage.BodyData.BodyAsString!),
_ => throw new NotSupportedException() _ => throw new NotSupportedException()
}; };
var fixedBytes = FixBytes(bytes, contentTypeHeaderValue); var fixedBytes = FixBytes(bytes, contentTypeHeader[0]);
return MimeMessage.Load(new MemoryStream(fixedBytes));
mimeMessage = MimeMessage.Load(new MemoryStream(fixedBytes));
return true;
}
mimeMessage = null;
return false;
} }
private static byte[] FixBytes(byte[] bytes, WireMockList<string> contentType) private static byte[] FixBytes(byte[] bytes, WireMockList<string> contentType)
@@ -1,3 +1,4 @@
using FluentAssertions;
using NFluent; using NFluent;
using WireMock.Matchers; using WireMock.Matchers;
using Xunit; using Xunit;
@@ -11,12 +12,13 @@ public class CSharpCodeMatcherTests
{ {
// Assign // Assign
string input = "x"; string input = "x";
// Act
var matcher = new CSharpCodeMatcher("return it == \"x\";"); var matcher = new CSharpCodeMatcher("return it == \"x\";");
// Act
var score = matcher.IsMatch(input).Score;
// Assert // Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(1.0d); score.Should().Be(MatchScores.Perfect);
} }
[Fact] [Fact]
@@ -24,12 +26,13 @@ public class CSharpCodeMatcherTests
{ {
// Assign // Assign
string input = "y"; string input = "y";
// Act
var matcher = new CSharpCodeMatcher("return it == \"x\";"); var matcher = new CSharpCodeMatcher("return it == \"x\";");
// Act
var score = matcher.IsMatch(input).Score;
// Assert // Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d); score.Should().Be(MatchScores.Mismatch);
} }
[Fact] [Fact]
@@ -37,12 +40,13 @@ public class CSharpCodeMatcherTests
{ {
// Assign // Assign
string input = "x"; string input = "x";
// Act
var matcher = new CSharpCodeMatcher(MatchBehaviour.RejectOnMatch, MatchOperator.Or, "return it == \"x\";"); var matcher = new CSharpCodeMatcher(MatchBehaviour.RejectOnMatch, MatchOperator.Or, "return it == \"x\";");
// Act
var score = matcher.IsMatch(input).Score;
// Assert // Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d); score.Should().Be(MatchScores.Mismatch);
} }
[Fact] [Fact]
@@ -55,12 +59,13 @@ public class CSharpCodeMatcherTests
Name = "Test" Name = "Test"
}; };
// Act
var matcher = new CSharpCodeMatcher("return it.Id > 1 && it.Name == \"Test\";"); var matcher = new CSharpCodeMatcher("return it.Id > 1 && it.Name == \"Test\";");
double match = matcher.IsMatch(input);
// Act
var score = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(1.0, match); score.Should().Be(MatchScores.Perfect);
} }
[Fact] [Fact]
@@ -1,3 +1,4 @@
using FluentAssertions;
using NFluent; using NFluent;
using WireMock.Matchers; using WireMock.Matchers;
using Xunit; using Xunit;
@@ -14,7 +15,12 @@ public class ContentTypeMatcherTests
public void ContentTypeMatcher_IsMatchWithIgnoreCaseFalse_Positive(string contentType) public void ContentTypeMatcher_IsMatchWithIgnoreCaseFalse_Positive(string contentType)
{ {
var matcher = new ContentTypeMatcher("application/json"); var matcher = new ContentTypeMatcher("application/json");
Check.That(matcher.IsMatch(contentType)).IsEqualTo(1.0d);
// Act
var score = matcher.IsMatch(contentType).Score;
// Assert
score.Should().Be(MatchScores.Perfect);
} }
[Theory] [Theory]
@@ -26,7 +32,12 @@ public class ContentTypeMatcherTests
public void ContentTypeMatcher_IsMatchWithIgnoreCaseTrue_Positive(string contentType) public void ContentTypeMatcher_IsMatchWithIgnoreCaseTrue_Positive(string contentType)
{ {
var matcher = new ContentTypeMatcher("application/json", true); var matcher = new ContentTypeMatcher("application/json", true);
Check.That(matcher.IsMatch(contentType)).IsEqualTo(1.0d);
// Act
var score = matcher.IsMatch(contentType).Score;
// Assert
score.Should().Be(MatchScores.Perfect);
} }
[Fact] [Fact]
@@ -39,7 +39,7 @@ public class ExactMatcherTests
var matcher = new ExactMatcher(true, "x"); var matcher = new ExactMatcher(true, "x");
// Act // Act
double result = matcher.IsMatch("X"); double result = matcher.IsMatch("X").Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
@@ -52,7 +52,7 @@ public class ExactMatcherTests
var matcher = new ExactMatcher("x"); var matcher = new ExactMatcher("x");
// Act // Act
double result = matcher.IsMatch("x"); double result = matcher.IsMatch("x").Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
@@ -65,7 +65,7 @@ public class ExactMatcherTests
var matcher = new ExactMatcher("x"); var matcher = new ExactMatcher("x");
// Act // Act
double result = matcher.IsMatch("y"); double result = matcher.IsMatch("y").Score;
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
@@ -78,7 +78,7 @@ public class ExactMatcherTests
var matcher = new ExactMatcher("x", "y"); var matcher = new ExactMatcher("x", "y");
// Act // Act
double result = matcher.IsMatch("x"); double result = matcher.IsMatch("x").Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
@@ -91,7 +91,7 @@ public class ExactMatcherTests
var matcher = new ExactMatcher("x", "y"); var matcher = new ExactMatcher("x", "y");
// Act // Act
double result = matcher.IsMatch("x"); double result = matcher.IsMatch("x").Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
@@ -104,10 +104,10 @@ public class ExactMatcherTests
public void ExactMatcher_IsMatch_WithMultiplePatterns_Average_ReturnsMatch(MatchOperator matchOperator, double score) public void ExactMatcher_IsMatch_WithMultiplePatterns_Average_ReturnsMatch(MatchOperator matchOperator, double score)
{ {
// Assign // Assign
var matcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, false, false, matchOperator, "x", "y"); var matcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, false, matchOperator, "x", "y");
// Act // Act
double result = matcher.IsMatch("x"); double result = matcher.IsMatch("x").Score;
// Assert // Assert
Check.That(result).IsEqualTo(score); Check.That(result).IsEqualTo(score);
@@ -120,7 +120,7 @@ public class ExactMatcherTests
var matcher = new ExactMatcher("cat"); var matcher = new ExactMatcher("cat");
// Act // Act
double result = matcher.IsMatch("caR"); double result = matcher.IsMatch("caR").Score;
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
@@ -130,10 +130,10 @@ public class ExactMatcherTests
public void ExactMatcher_IsMatch_SinglePattern_AcceptOnMatch() public void ExactMatcher_IsMatch_SinglePattern_AcceptOnMatch()
{ {
// Assign // Assign
var matcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, false, false, MatchOperator.Or, "cat"); var matcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, "cat");
// Act // Act
double result = matcher.IsMatch("cat"); double result = matcher.IsMatch("cat").Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
@@ -143,10 +143,10 @@ public class ExactMatcherTests
public void ExactMatcher_IsMatch_SinglePattern_RejectOnMatch() public void ExactMatcher_IsMatch_SinglePattern_RejectOnMatch()
{ {
// Assign // Assign
var matcher = new ExactMatcher(MatchBehaviour.RejectOnMatch, false, false, MatchOperator.Or, "cat"); var matcher = new ExactMatcher(MatchBehaviour.RejectOnMatch, false, MatchOperator.Or, "cat");
// Act // Act
double result = matcher.IsMatch("cat"); double result = matcher.IsMatch("cat").Score;
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
@@ -14,7 +14,7 @@ public class ExactObjectMatcherTests
// Act // Act
var matcher = new ExactObjectMatcher(obj); var matcher = new ExactObjectMatcher(obj);
string name = matcher.Name; var name = matcher.Name;
// Assert // Assert
Check.That(name).Equals("ExactObjectMatcher"); Check.That(name).Equals("ExactObjectMatcher");
@@ -28,10 +28,10 @@ public class ExactObjectMatcherTests
// Act // Act
var matcher = new ExactObjectMatcher(new byte[] { 1, 2 }); var matcher = new ExactObjectMatcher(new byte[] { 1, 2 });
double result = matcher.IsMatch(checkValue); var score = matcher.IsMatch(checkValue).Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(score).IsEqualTo(1.0);
} }
[Fact] [Fact]
@@ -42,10 +42,10 @@ public class ExactObjectMatcherTests
// Act // Act
var matcher = new ExactObjectMatcher(obj); var matcher = new ExactObjectMatcher(obj);
double result = matcher.IsMatch(new { x = 500, s = "s" }); var score = matcher.IsMatch(new { x = 500, s = "s" }).Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(score).IsEqualTo(1.0);
} }
[Fact] [Fact]
@@ -56,9 +56,9 @@ public class ExactObjectMatcherTests
// Act // Act
var matcher = new ExactObjectMatcher(MatchBehaviour.RejectOnMatch, obj); var matcher = new ExactObjectMatcher(MatchBehaviour.RejectOnMatch, obj);
double result = matcher.IsMatch(new { x = 500, s = "s" }); var score = matcher.IsMatch(new { x = 500, s = "s" }).Score;
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(score).IsEqualTo(0.0);
} }
} }
@@ -51,7 +51,7 @@ public class GraphQLMatcherTests
var result = matcher.IsMatch(input); var result = matcher.IsMatch(input);
// Assert // Assert
result.Should().Be(MatchScores.Perfect); result.Score.Should().Be(MatchScores.Perfect);
matcher.GetPatterns().Should().Contain(TestSchema); matcher.GetPatterns().Should().Contain(TestSchema);
} }
@@ -71,7 +71,7 @@ public class GraphQLMatcherTests
var result = matcher.IsMatch(input); var result = matcher.IsMatch(input);
// Assert // Assert
result.Should().Be(MatchScores.Perfect); result.Score.Should().Be(MatchScores.Perfect);
matcher.GetPatterns().Should().Contain(TestSchema); matcher.GetPatterns().Should().Contain(TestSchema);
} }
@@ -93,7 +93,7 @@ public class GraphQLMatcherTests
var result = matcher.IsMatch(input); var result = matcher.IsMatch(input);
// Assert // Assert
result.Should().Be(MatchScores.Mismatch); result.Score.Should().Be(MatchScores.Mismatch);
} }
[Fact] [Fact]
@@ -111,21 +111,22 @@ public class GraphQLMatcherTests
var result = matcher.IsMatch(input); var result = matcher.IsMatch(input);
// Assert // Assert
result.Should().Be(MatchScores.Perfect); result.Score.Should().Be(MatchScores.Perfect);
} }
[Fact] [Fact]
public void GraphQLMatcher_For_ValidSchema_And_IncorrectQueryWithError_WithThrowExceptionTrue_ThrowsException() public void GraphQLMatcher_For_ValidSchema_And_IncorrectQueryWithError_WithThrowExceptionTrue_ReturnsError()
{ {
// Arrange // Arrange
var input = "{\"query\":\"{\\r\\n studentsX {\\r\\n fullName\\r\\n X\\r\\n }\\r\\n}\"}"; var input = "{\"query\":\"{\\r\\n studentsX {\\r\\n fullName\\r\\n X\\r\\n }\\r\\n}\"}";
// Act // Act
var matcher = new GraphQLMatcher(TestSchema, MatchBehaviour.AcceptOnMatch, true); var matcher = new GraphQLMatcher(TestSchema);
Action action = () => matcher.IsMatch(input); var result = matcher.IsMatch(input);
// Assert // Assert
action.Should().Throw<Exception>(); result.Score.Should().Be(MatchScores.Mismatch);
result.Exception!.Message.Should().StartWith("Cannot query field 'studentsX' on type 'Query'");
} }
[Fact] [Fact]
@@ -42,7 +42,7 @@ public class JmesPathMatcherTests
var matcher = new JmesPathMatcher(""); var matcher = new JmesPathMatcher("");
// Act // Act
double match = matcher.IsMatch(bytes); double match = matcher.IsMatch(bytes).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -56,7 +56,7 @@ public class JmesPathMatcherTests
var matcher = new JmesPathMatcher(""); var matcher = new JmesPathMatcher("");
// Act // Act
double match = matcher.IsMatch(s); double match = matcher.IsMatch(s).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -70,7 +70,7 @@ public class JmesPathMatcherTests
var matcher = new JmesPathMatcher(""); var matcher = new JmesPathMatcher("");
// Act // Act
double match = matcher.IsMatch(o); double match = matcher.IsMatch(o).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -83,7 +83,7 @@ public class JmesPathMatcherTests
var matcher = new JmesPathMatcher("xxx"); var matcher = new JmesPathMatcher("xxx");
// Act // Act
double match = matcher.IsMatch(""); double match = matcher.IsMatch("").Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -96,7 +96,7 @@ public class JmesPathMatcherTests
var matcher = new JmesPathMatcher(""); var matcher = new JmesPathMatcher("");
// Act // Act
double match = matcher.IsMatch("x"); double match = matcher.IsMatch("x").Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -109,7 +109,7 @@ public class JmesPathMatcherTests
var matcher = new JmesPathMatcher("things.name == 'RequiredThing'"); var matcher = new JmesPathMatcher("things.name == 'RequiredThing'");
// Act // Act
double match = matcher.IsMatch(new { things = new { name = "RequiredThing" } }); double match = matcher.IsMatch(new { things = new { name = "RequiredThing" } }).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
@@ -132,7 +132,7 @@ public class JmesPathMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "things", sub } { "things", sub }
}; };
double match = matcher.IsMatch(jobject); double match = matcher.IsMatch(jobject).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
@@ -145,7 +145,7 @@ public class JmesPathMatcherTests
var matcher = new JmesPathMatcher("things.x == 'RequiredThing'"); var matcher = new JmesPathMatcher("things.x == 'RequiredThing'");
// Act // Act
double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }")); double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
@@ -155,10 +155,10 @@ public class JmesPathMatcherTests
public void JmesPathMatcher_IsMatch_RejectOnMatch() public void JmesPathMatcher_IsMatch_RejectOnMatch()
{ {
// Assign // Assign
var matcher = new JmesPathMatcher(MatchBehaviour.RejectOnMatch, false, MatchOperator.Or, "things.x == 'RequiredThing'"); var matcher = new JmesPathMatcher(MatchBehaviour.RejectOnMatch, MatchOperator.Or, "things.x == 'RequiredThing'");
// Act // Act
double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }")); double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0.0); Check.That(match).IsEqualTo(0.0);
@@ -82,29 +82,17 @@ public class JsonMatcherTests
} }
[Fact] [Fact]
public void JsonMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsFalse_Should_ReturnMismatch() public void JsonMatcher_IsMatch_WithInvalidValue_Should_ReturnMismatch_And_Exception_ShouldBeSet()
{ {
// Assign // Assign
var matcher = new JsonMatcher(""); var matcher = new JsonMatcher("");
// Act // Act
double match = matcher.IsMatch(new MemoryStream()); var result = matcher.IsMatch(new MemoryStream());
// Assert // Assert
Check.That(match).IsEqualTo(0); result.Score.Should().Be(MatchScores.Mismatch);
} result.Exception.Should().BeAssignableTo<JsonException>();
[Fact]
public void JsonMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsTrue_Should_ReturnMismatch()
{
// Assign
var matcher = new JsonMatcher("", false, true);
// Act
Action action = () => matcher.IsMatch(new MemoryStream());
// Assert
action.Should().Throw<JsonException>();
} }
[Fact] [Fact]
@@ -115,7 +103,7 @@ public class JsonMatcherTests
var matcher = new JsonMatcher(""); var matcher = new JsonMatcher("");
// Act // Act
double match = matcher.IsMatch(bytes); double match = matcher.IsMatch(bytes).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -129,7 +117,7 @@ public class JsonMatcherTests
var matcher = new JsonMatcher(""); var matcher = new JsonMatcher("");
// Act // Act
double match = matcher.IsMatch(s); double match = matcher.IsMatch(s).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -143,7 +131,7 @@ public class JsonMatcherTests
var matcher = new JsonMatcher(""); var matcher = new JsonMatcher("");
// Act // Act
double match = matcher.IsMatch(o); double match = matcher.IsMatch(o).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -161,7 +149,7 @@ public class JsonMatcherTests
"x", "x",
"y" "y"
}; };
double match = matcher.IsMatch(jArray); double match = matcher.IsMatch(jArray).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -179,7 +167,7 @@ public class JsonMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -197,7 +185,7 @@ public class JsonMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "NaMe", new JValue("Test") } { "NaMe", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -211,7 +199,7 @@ public class JsonMatcherTests
// Act // Act
var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -225,7 +213,7 @@ public class JsonMatcherTests
// Act // Act
var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -243,7 +231,7 @@ public class JsonMatcherTests
"x", "x",
"y" "y"
}; };
double match = matcher.IsMatch(jArray); double match = matcher.IsMatch(jArray).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -261,7 +249,7 @@ public class JsonMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -279,7 +267,7 @@ public class JsonMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -297,7 +285,7 @@ public class JsonMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(0.0, match); Assert.Equal(0.0, match);
@@ -314,7 +302,7 @@ public class JsonMatcherTests
{ {
{ "preferredAt", new JValue("2019-11-21T10:32:53.2210009+00:00") } { "preferredAt", new JValue("2019-11-21T10:32:53.2210009+00:00") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -331,7 +319,7 @@ public class JsonMatcherTests
{ {
{ "NormalEnum", new JValue(0) } { "NormalEnum", new JValue(0) }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
match.Should().Be(1.0); match.Should().Be(1.0);
@@ -348,7 +336,7 @@ public class JsonMatcherTests
{ {
{ "EnumWithJsonConverter", new JValue("Type1") } { "EnumWithJsonConverter", new JValue("Type1") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
match.Should().Be(1.0); match.Should().Be(1.0);
@@ -60,29 +60,17 @@ public class JsonPartialMatcherTests
} }
[Fact] [Fact]
public void JsonPartialMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsFalse_Should_ReturnMismatch() public void JsonPartialMatcher_IsMatch_WithInvalidValue_Should_ReturnMismatch_And_Exception_ShouldBeSet()
{ {
// Assign // Assign
var matcher = new JsonPartialMatcher(""); var matcher = new JsonPartialMatcher("");
// Act // Act
double match = matcher.IsMatch(new MemoryStream()); var result = matcher.IsMatch(new MemoryStream());
// Assert // Assert
Check.That(match).IsEqualTo(0); result.Score.Should().Be(MatchScores.Mismatch);
} result.Exception.Should().BeAssignableTo<JsonException>();
[Fact]
public void JsonPartialMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsTrue_Should_ReturnMismatch()
{
// Assign
var matcher = new JsonPartialMatcher("", false, true);
// Act
Action action = () => matcher.IsMatch(new MemoryStream());
// Assert
action.Should().Throw<JsonException>();
} }
[Fact] [Fact]
@@ -93,7 +81,7 @@ public class JsonPartialMatcherTests
var matcher = new JsonPartialMatcher(""); var matcher = new JsonPartialMatcher("");
// Act // Act
double match = matcher.IsMatch(bytes); double match = matcher.IsMatch(bytes).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -107,7 +95,7 @@ public class JsonPartialMatcherTests
var matcher = new JsonPartialMatcher(""); var matcher = new JsonPartialMatcher("");
// Act // Act
double match = matcher.IsMatch(s); double match = matcher.IsMatch(s).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -121,7 +109,7 @@ public class JsonPartialMatcherTests
var matcher = new JsonPartialMatcher(""); var matcher = new JsonPartialMatcher("");
// Act // Act
double match = matcher.IsMatch(o); double match = matcher.IsMatch(o).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -139,7 +127,7 @@ public class JsonPartialMatcherTests
"x", "x",
"y" "y"
}; };
double match = matcher.IsMatch(jArray); double match = matcher.IsMatch(jArray).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -157,7 +145,7 @@ public class JsonPartialMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -167,7 +155,7 @@ public class JsonPartialMatcherTests
public void JsonPartialMatcher_IsMatch_WithRegexTrue() public void JsonPartialMatcher_IsMatch_WithRegexTrue()
{ {
// Assign // Assign
var matcher = new JsonPartialMatcher(new { Id = "^\\d+$", Name = "Test" }, false, false, true); var matcher = new JsonPartialMatcher(new { Id = "^\\d+$", Name = "Test" }, false, true);
// Act // Act
var jObject = new JObject var jObject = new JObject
@@ -175,7 +163,7 @@ public class JsonPartialMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -193,7 +181,7 @@ public class JsonPartialMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(0.0, match); Assert.Equal(0.0, match);
@@ -203,10 +191,11 @@ public class JsonPartialMatcherTests
public void JsonPartialMatcher_IsMatch_GuidAsString_UsingRegex() public void JsonPartialMatcher_IsMatch_GuidAsString_UsingRegex()
{ {
var guid = new Guid("1111238e-b775-44a9-a263-95e570135c94"); var guid = new Guid("1111238e-b775-44a9-a263-95e570135c94");
var matcher = new JsonPartialMatcher(new { var matcher = new JsonPartialMatcher(new
{
Id = 1, Id = 1,
Name = "^1111[a-fA-F0-9]{4}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$" Name = "^1111[a-fA-F0-9]{4}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"
}, false, false, true); }, false, true);
// Act // Act
var jObject = new JObject var jObject = new JObject
@@ -214,7 +203,7 @@ public class JsonPartialMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue(guid) } { "Name", new JValue(guid) }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -232,7 +221,7 @@ public class JsonPartialMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "NaMe", new JValue("Test") } { "NaMe", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -246,7 +235,7 @@ public class JsonPartialMatcherTests
// Act // Act
var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -260,7 +249,7 @@ public class JsonPartialMatcherTests
// Act // Act
var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -278,7 +267,7 @@ public class JsonPartialMatcherTests
"x", "x",
"y" "y"
}; };
double match = matcher.IsMatch(jArray); double match = matcher.IsMatch(jArray).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -296,7 +285,7 @@ public class JsonPartialMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -305,20 +294,20 @@ public class JsonPartialMatcherTests
[Fact] [Fact]
public void JsonPartialMatcher_IsMatch_GuidAsString() public void JsonPartialMatcher_IsMatch_GuidAsString()
{ {
// Assign // Assign
var guid = Guid.NewGuid(); var guid = Guid.NewGuid();
var matcher = new JsonPartialMatcher(new { Id = 1, Name = guid }); var matcher = new JsonPartialMatcher(new { Id = 1, Name = guid });
// Act // Act
var jObject = new JObject var jObject = new JObject
{ {
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue(guid.ToString()) } { "Name", new JValue(guid.ToString()) }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
} }
[Fact] [Fact]
@@ -333,7 +322,7 @@ public class JsonPartialMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -351,7 +340,7 @@ public class JsonPartialMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(0.0, match); Assert.Equal(0.0, match);
@@ -368,7 +357,7 @@ public class JsonPartialMatcherTests
{ {
{ "preferredAt", new JValue("2019-11-21T10:32:53.2210009+00:00") } { "preferredAt", new JValue("2019-11-21T10:32:53.2210009+00:00") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -391,7 +380,7 @@ public class JsonPartialMatcherTests
var matcher = new JsonPartialMatcher(value); var matcher = new JsonPartialMatcher(value);
// Act // Act
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -415,7 +404,7 @@ public class JsonPartialMatcherTests
var matcher = new JsonPartialMatcher(value); var matcher = new JsonPartialMatcher(value);
// Act // Act
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(0.0, match); Assert.Equal(0.0, match);
@@ -434,7 +423,7 @@ public class JsonPartialMatcherTests
var matcher = new JsonPartialMatcher(value); var matcher = new JsonPartialMatcher(value);
// Act // Act
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -453,7 +442,7 @@ public class JsonPartialMatcherTests
var matcher = new JsonPartialMatcher(value); var matcher = new JsonPartialMatcher(value);
// Act // Act
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(0.0, match); Assert.Equal(0.0, match);
@@ -60,29 +60,17 @@ public class JsonPartialWildcardMatcherTests
} }
[Fact] [Fact]
public void JsonPartialWildcardMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsFalse_Should_ReturnMismatch() public void JsonPartialWildcardMatcher_IsMatch_WithInvalidValue_Should_ReturnMismatch_And_Exception_ShouldBeSet()
{ {
// Assign // Assign
var matcher = new JsonPartialWildcardMatcher(""); var matcher = new JsonPartialWildcardMatcher("");
// Act // Act
double match = matcher.IsMatch(new MemoryStream()); var result = matcher.IsMatch(new MemoryStream());
// Assert // Assert
Check.That(match).IsEqualTo(0); result.Score.Should().Be(MatchScores.Mismatch);
} result.Exception.Should().BeAssignableTo<JsonException>();
[Fact]
public void JsonPartialWildcardMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsTrue_Should_ReturnMismatch()
{
// Assign
var matcher = new JsonPartialWildcardMatcher("", false, true);
// Act
Action action = () => matcher.IsMatch(new MemoryStream());
// Assert
action.Should().Throw<JsonException>();
} }
[Fact] [Fact]
@@ -93,7 +81,7 @@ public class JsonPartialWildcardMatcherTests
var matcher = new JsonPartialWildcardMatcher(""); var matcher = new JsonPartialWildcardMatcher("");
// Act // Act
double match = matcher.IsMatch(bytes); double match = matcher.IsMatch(bytes).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -107,7 +95,7 @@ public class JsonPartialWildcardMatcherTests
var matcher = new JsonPartialWildcardMatcher(""); var matcher = new JsonPartialWildcardMatcher("");
// Act // Act
double match = matcher.IsMatch(s); double match = matcher.IsMatch(s).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -121,7 +109,7 @@ public class JsonPartialWildcardMatcherTests
var matcher = new JsonPartialWildcardMatcher(""); var matcher = new JsonPartialWildcardMatcher("");
// Act // Act
double match = matcher.IsMatch(o); double match = matcher.IsMatch(o).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -139,7 +127,7 @@ public class JsonPartialWildcardMatcherTests
"x", "x",
"y" "y"
}; };
double match = matcher.IsMatch(jArray); double match = matcher.IsMatch(jArray).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -157,7 +145,7 @@ public class JsonPartialWildcardMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -175,7 +163,7 @@ public class JsonPartialWildcardMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "NaMe", new JValue("Test") } { "NaMe", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -189,7 +177,7 @@ public class JsonPartialWildcardMatcherTests
// Act // Act
var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -203,7 +191,7 @@ public class JsonPartialWildcardMatcherTests
// Act // Act
var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -221,7 +209,7 @@ public class JsonPartialWildcardMatcherTests
"x", "x",
"y" "y"
}; };
double match = matcher.IsMatch(jArray); double match = matcher.IsMatch(jArray).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -239,7 +227,7 @@ public class JsonPartialWildcardMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -257,7 +245,7 @@ public class JsonPartialWildcardMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -275,7 +263,7 @@ public class JsonPartialWildcardMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(0.0, match); Assert.Equal(0.0, match);
@@ -292,7 +280,7 @@ public class JsonPartialWildcardMatcherTests
{ {
{ "preferredAt", new JValue("2019-11-21T10:32:53.2210009+00:00") } { "preferredAt", new JValue("2019-11-21T10:32:53.2210009+00:00") }
}; };
double match = matcher.IsMatch(jObject); double match = matcher.IsMatch(jObject).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -315,7 +303,7 @@ public class JsonPartialWildcardMatcherTests
var matcher = new JsonPartialWildcardMatcher(value); var matcher = new JsonPartialWildcardMatcher(value);
// Act // Act
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -330,7 +318,7 @@ public class JsonPartialWildcardMatcherTests
var matcher = new JsonPartialWildcardMatcher(value); var matcher = new JsonPartialWildcardMatcher(value);
// Act // Act
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
match.Should().Be(1.0); match.Should().Be(1.0);
@@ -354,7 +342,7 @@ public class JsonPartialWildcardMatcherTests
var matcher = new JsonPartialWildcardMatcher(value); var matcher = new JsonPartialWildcardMatcher(value);
// Act // Act
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(0.0, match); Assert.Equal(0.0, match);
@@ -373,7 +361,7 @@ public class JsonPartialWildcardMatcherTests
var matcher = new JsonPartialWildcardMatcher(value); var matcher = new JsonPartialWildcardMatcher(value);
// Act // Act
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -392,7 +380,7 @@ public class JsonPartialWildcardMatcherTests
var matcher = new JsonPartialWildcardMatcher(value); var matcher = new JsonPartialWildcardMatcher(value);
// Act // Act
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(0.0, match); Assert.Equal(0.0, match);
@@ -42,7 +42,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher(""); var matcher = new JsonPathMatcher("");
// Act // Act
double match = matcher.IsMatch(bytes); double match = matcher.IsMatch(bytes).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -56,7 +56,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher(""); var matcher = new JsonPathMatcher("");
// Act // Act
double match = matcher.IsMatch(s); double match = matcher.IsMatch(s).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -70,7 +70,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher(""); var matcher = new JsonPathMatcher("");
// Act // Act
double match = matcher.IsMatch(o); double match = matcher.IsMatch(o).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -83,7 +83,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher("xxx"); var matcher = new JsonPathMatcher("xxx");
// Act // Act
double match = matcher.IsMatch(""); double match = matcher.IsMatch("").Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -96,7 +96,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher(""); var matcher = new JsonPathMatcher("");
// Act // Act
double match = matcher.IsMatch("x"); double match = matcher.IsMatch("x").Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -109,7 +109,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]"); var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]");
// Act // Act
double match = matcher.IsMatch(new { Id = 1, Name = "Test" }); double match = matcher.IsMatch(new { Id = 1, Name = "Test" }).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
@@ -122,7 +122,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher("$.things[?(@.name == 'x')]"); var matcher = new JsonPathMatcher("$.things[?(@.name == 'x')]");
// Act // Act
double match = matcher.IsMatch(new { things = new { name = "x" } }); double match = matcher.IsMatch(new { things = new { name = "x" } }).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
@@ -136,7 +136,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher("$.things[?(@.name == 'x')]"); var matcher = new JsonPathMatcher("$.things[?(@.name == 'x')]");
// Act // Act
double match = matcher.IsMatch(json); double match = matcher.IsMatch(json).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
@@ -150,7 +150,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher("$.things[?(@.name == 'x')]"); var matcher = new JsonPathMatcher("$.things[?(@.name == 'x')]");
// Act // Act
double match = matcher.IsMatch(json); double match = matcher.IsMatch(json).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
@@ -169,7 +169,7 @@ public class JsonPathMatcherTests
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jobject); double match = matcher.IsMatch(jobject).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
@@ -182,7 +182,7 @@ public class JsonPathMatcherTests
var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]"); var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]");
// Act // Act
double match = matcher.IsMatch(JObject.Parse("{\"Id\":1,\"Name\":\"Test\"}")); double match = matcher.IsMatch(JObject.Parse("{\"Id\":1,\"Name\":\"Test\"}")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
@@ -192,10 +192,10 @@ public class JsonPathMatcherTests
public void JsonPathMatcher_IsMatch_RejectOnMatch() public void JsonPathMatcher_IsMatch_RejectOnMatch()
{ {
// Arrange // Arrange
var matcher = new JsonPathMatcher(MatchBehaviour.RejectOnMatch, false, MatchOperator.Or, "$..[?(@.Id == 1)]"); var matcher = new JsonPathMatcher(MatchBehaviour.RejectOnMatch, MatchOperator.Or, "$..[?(@.Id == 1)]");
// Act // Act
double match = matcher.IsMatch(JObject.Parse("{\"Id\":1,\"Name\":\"Test\"}")); double match = matcher.IsMatch(JObject.Parse("{\"Id\":1,\"Name\":\"Test\"}")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0.0); Check.That(match).IsEqualTo(0.0);
@@ -215,7 +215,7 @@ public class JsonPathMatcherTests
""arr"": [{ ""arr"": [{
""line1"": ""line1"", ""line1"": ""line1"",
}] }]
}")); }")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1.0); Check.That(match).IsEqualTo(1.0);
@@ -237,10 +237,10 @@ public class JsonPathMatcherTests
""line1"": ""line1"", ""line1"": ""line1"",
} }
] ]
}")); }")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1.0); Check.That(match).IsEqualTo(1.0);
} }
[Fact] [Fact]
@@ -259,7 +259,7 @@ public class JsonPathMatcherTests
""line1"": ""line1"", ""line1"": ""line1"",
} }
] ]
}")); }")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0.0); Check.That(match).IsEqualTo(0.0);
@@ -277,7 +277,7 @@ public class JsonPathMatcherTests
""test"": ""test"", ""test"": ""test"",
""test2"": ""test2"", ""test2"": ""test2"",
""arr"": [] ""arr"": []
}")); }")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0.0); Check.That(match).IsEqualTo(0.0);
@@ -295,7 +295,7 @@ public class JsonPathMatcherTests
""test"": ""test"", ""test"": ""test"",
""test2"": ""test2"", ""test2"": ""test2"",
""arr"": [] ""arr"": []
}")); }")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(0.0); Check.That(match).IsEqualTo(0.0);
@@ -319,9 +319,9 @@ public class JsonPathMatcherTests
""subline1"":""subline1"" ""subline1"":""subline1""
}] }]
}] }]
}")); }")).Score;
// Assert // Assert
Check.That(match).IsEqualTo(1.0); Check.That(match).IsEqualTo(1.0);
} }
} }
@@ -1,3 +1,4 @@
using FluentAssertions;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NFluent; using NFluent;
using WireMock.Matchers; using WireMock.Matchers;
@@ -17,7 +18,8 @@ public class LinqMatcherTests
var matcher = new LinqMatcher("DateTime.Parse(it) > \"2018-08-01 13:50:00\""); var matcher = new LinqMatcher("DateTime.Parse(it) > \"2018-08-01 13:50:00\"");
// Assert // Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(1.0d); var score = matcher.IsMatch(input).Score;
score.Should().Be(MatchScores.Perfect);
} }
[Fact] [Fact]
@@ -30,7 +32,8 @@ public class LinqMatcherTests
var matcher = new LinqMatcher("DateTime.Parse(it) > \"2019-01-01 00:00:00\""); var matcher = new LinqMatcher("DateTime.Parse(it) > \"2019-01-01 00:00:00\"");
// Assert // Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d); var score = matcher.IsMatch(input).Score;
score.Should().Be(MatchScores.Mismatch);
} }
[Fact] [Fact]
@@ -43,7 +46,8 @@ public class LinqMatcherTests
var matcher = new LinqMatcher(MatchBehaviour.RejectOnMatch, "DateTime.Parse(it) > \"2018-08-01 13:50:00\""); var matcher = new LinqMatcher(MatchBehaviour.RejectOnMatch, "DateTime.Parse(it) > \"2018-08-01 13:50:00\"");
// Assert // Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d); var score = matcher.IsMatch(input).Score;
score.Should().Be(MatchScores.Mismatch);
} }
[Fact] [Fact]
@@ -58,7 +62,7 @@ public class LinqMatcherTests
// Act // Act
var matcher = new LinqMatcher("Id > 1 AND Name == \"Test\""); var matcher = new LinqMatcher("Id > 1 AND Name == \"Test\"");
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -77,7 +81,7 @@ public class LinqMatcherTests
// Act // Act
var matcher = new LinqMatcher("IntegerId > 1 AND LongId > 1 && Name == \"Test\""); var matcher = new LinqMatcher("IntegerId > 1 AND LongId > 1 && Name == \"Test\"");
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input).Score;
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
@@ -55,7 +55,7 @@ AAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC
// Assert // Assert
matcher.Name.Should().Be("MimePartMatcher"); matcher.Name.Should().Be("MimePartMatcher");
result.Should().Be(MatchScores.Perfect); result.Score.Should().Be(MatchScores.Perfect);
} }
[Fact] [Fact]
@@ -73,7 +73,7 @@ AAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC
var result = matcher.IsMatch(part); var result = matcher.IsMatch(part);
// Assert // Assert
result.Should().Be(MatchScores.Perfect); result.Score.Should().Be(MatchScores.Perfect);
} }
[Fact] [Fact]
@@ -93,7 +93,7 @@ AAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC
var result = matcher.IsMatch(part); var result = matcher.IsMatch(part);
// Assert // Assert
result.Should().Be(MatchScores.Perfect); result.Score.Should().Be(MatchScores.Perfect);
} }
} }
#endif #endif
@@ -12,7 +12,7 @@ public class NotNullOrEmptyMatcherTests
{ {
// Act // Act
var matcher = new NotNullOrEmptyMatcher(); var matcher = new NotNullOrEmptyMatcher();
string name = matcher.Name; var name = matcher.Name;
// Assert // Assert
Check.That(name).Equals("NotNullOrEmptyMatcher"); Check.That(name).Equals("NotNullOrEmptyMatcher");
@@ -26,7 +26,7 @@ public class NotNullOrEmptyMatcherTests
{ {
// Act // Act
var matcher = new NotNullOrEmptyMatcher(); var matcher = new NotNullOrEmptyMatcher();
double result = matcher.IsMatch(data); var result = matcher.IsMatch(data).Score;
// Assert // Assert
result.Should().Be(expected); result.Should().Be(expected);
@@ -40,7 +40,7 @@ public class NotNullOrEmptyMatcherTests
{ {
// Act // Act
var matcher = new NotNullOrEmptyMatcher(); var matcher = new NotNullOrEmptyMatcher();
double result = matcher.IsMatch(@string); var result = matcher.IsMatch(@string).Score;
// Assert // Assert
result.Should().Be(expected); result.Should().Be(expected);
@@ -54,7 +54,7 @@ public class NotNullOrEmptyMatcherTests
{ {
// Act // Act
var matcher = new NotNullOrEmptyMatcher(); var matcher = new NotNullOrEmptyMatcher();
double result = matcher.IsMatch((object)@string); var result = matcher.IsMatch((object)@string).Score;
// Assert // Assert
result.Should().Be(expected); result.Should().Be(expected);
@@ -65,7 +65,7 @@ public class NotNullOrEmptyMatcherTests
{ {
// Act // Act
var matcher = new NotNullOrEmptyMatcher(); var matcher = new NotNullOrEmptyMatcher();
double result = matcher.IsMatch(new { x = "x" }); var result = matcher.IsMatch(new { x = "x" }).Score;
// Assert // Assert
result.Should().Be(1.0); result.Should().Be(1.0);
@@ -53,7 +53,7 @@ public class RegexMatcherTests
var matcher = new RegexMatcher("H.*o"); var matcher = new RegexMatcher("H.*o");
// Act // Act
double result = matcher.IsMatch("Hello world!"); double result = matcher.IsMatch("Hello world!").Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0d); Check.That(result).IsEqualTo(1.0d);
@@ -66,7 +66,7 @@ public class RegexMatcherTests
var matcher = new RegexMatcher("H.*o"); var matcher = new RegexMatcher("H.*o");
// Act // Act
double result = matcher.IsMatch(null); double result = matcher.IsMatch(null).Score;
// Assert // Assert
Check.That(result).IsEqualTo(0.0d); Check.That(result).IsEqualTo(0.0d);
@@ -79,7 +79,7 @@ public class RegexMatcherTests
var matcher = new RegexMatcher(@"\GUIDB", true); var matcher = new RegexMatcher(@"\GUIDB", true);
// Act // Act
double result = matcher.IsMatch(Guid.NewGuid().ToString("B")); double result = matcher.IsMatch(Guid.NewGuid().ToString("B")).Score;
// Assert // Assert
result.Should().Be(1.0); result.Should().Be(1.0);
@@ -89,10 +89,10 @@ public class RegexMatcherTests
public void RegexMatcher_IsMatch_Regex_Guid() public void RegexMatcher_IsMatch_Regex_Guid()
{ {
// Assign // Assign
var matcher = new RegexMatcher(@"\GUIDB", true, false, false); var matcher = new RegexMatcher(@"\GUIDB", true, false);
// Act // Act
double result = matcher.IsMatch(Guid.NewGuid().ToString("B")); double result = matcher.IsMatch(Guid.NewGuid().ToString("B")).Score;
// Assert // Assert
result.Should().Be(0); result.Should().Be(0);
@@ -105,7 +105,7 @@ public class RegexMatcherTests
var matcher = new RegexMatcher("H.*o", true); var matcher = new RegexMatcher("H.*o", true);
// Act // Act
double result = matcher.IsMatch("hello"); double result = matcher.IsMatch("hello").Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0d); Check.That(result).IsEqualTo(1.0d);
@@ -118,7 +118,7 @@ public class RegexMatcherTests
var matcher = new RegexMatcher(MatchBehaviour.RejectOnMatch, "h.*o"); var matcher = new RegexMatcher(MatchBehaviour.RejectOnMatch, "h.*o");
// Act // Act
double result = matcher.IsMatch("hello"); double result = matcher.IsMatch("hello").Score;
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
@@ -13,12 +13,12 @@ public class RequestMatchResultTests
{ {
// Arrange // Arrange
var result1 = new RequestMatchResult(); var result1 = new RequestMatchResult();
result1.AddScore(typeof(WildcardMatcher), 1); result1.AddScore(typeof(WildcardMatcher), 1, null);
result1.AddScore(typeof(WildcardMatcher), 0.9); result1.AddScore(typeof(WildcardMatcher), 0.9, null);
var result2 = new RequestMatchResult(); var result2 = new RequestMatchResult();
result2.AddScore(typeof(LinqMatcher), 1); result2.AddScore(typeof(LinqMatcher), 1, null);
result2.AddScore(typeof(LinqMatcher), 1); result2.AddScore(typeof(LinqMatcher), 1, null);
var results = new[] { result1, result2 }; var results = new[] { result1, result2 };
@@ -34,13 +34,13 @@ public class RequestMatchResultTests
{ {
// Arrange // Arrange
var result1 = new RequestMatchResult(); var result1 = new RequestMatchResult();
result1.AddScore(typeof(WildcardMatcher), 1); result1.AddScore(typeof(WildcardMatcher), 1, null);
result1.AddScore(typeof(WildcardMatcher), 1); result1.AddScore(typeof(WildcardMatcher), 1, null);
var result2 = new RequestMatchResult(); var result2 = new RequestMatchResult();
result2.AddScore(typeof(LinqMatcher), 1); result2.AddScore(typeof(LinqMatcher), 1, null);
result2.AddScore(typeof(LinqMatcher), 1); result2.AddScore(typeof(LinqMatcher), 1, null);
result2.AddScore(typeof(LinqMatcher), 1); result2.AddScore(typeof(LinqMatcher), 1, null);
var results = new[] { result1, result2 }; var results = new[] { result1, result2 };
@@ -39,7 +39,7 @@ public class SimMetricsMatcherTests
var matcher = new SimMetricsMatcher("The cat walks in the street."); var matcher = new SimMetricsMatcher("The cat walks in the street.");
// Act // Act
double result = matcher.IsMatch("The car drives in the street."); double result = matcher.IsMatch("The car drives in the street.").Score;
// Assert // Assert
Check.That(result).IsStrictlyLessThan(1.0).And.IsStrictlyGreaterThan(0.5); Check.That(result).IsStrictlyLessThan(1.0).And.IsStrictlyGreaterThan(0.5);
@@ -52,7 +52,7 @@ public class SimMetricsMatcherTests
var matcher = new SimMetricsMatcher("The cat walks in the street."); var matcher = new SimMetricsMatcher("The cat walks in the street.");
// Act // Act
double result = matcher.IsMatch("Hello"); double result = matcher.IsMatch("Hello").Score;
// Assert // Assert
Check.That(result).IsStrictlyLessThan(0.1).And.IsStrictlyGreaterThan(0.05); Check.That(result).IsStrictlyLessThan(0.1).And.IsStrictlyGreaterThan(0.05);
@@ -65,7 +65,7 @@ public class SimMetricsMatcherTests
var matcher = new SimMetricsMatcher("test"); var matcher = new SimMetricsMatcher("test");
// Act // Act
double result = matcher.IsMatch("test"); double result = matcher.IsMatch("test").Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
@@ -78,7 +78,7 @@ public class SimMetricsMatcherTests
var matcher = new SimMetricsMatcher(MatchBehaviour.RejectOnMatch, "test"); var matcher = new SimMetricsMatcher(MatchBehaviour.RejectOnMatch, "test");
// Act // Act
double result = matcher.IsMatch("test"); double result = matcher.IsMatch("test").Score;
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
@@ -19,11 +19,13 @@ public class WildcardMatcherTest
PatternAsFile = "pf" PatternAsFile = "pf"
}; };
// Act
var matcher = new WildcardMatcher(pattern); var matcher = new WildcardMatcher(pattern);
// Act
var score = matcher.IsMatch("a").Score;
// Assert // Assert
matcher.IsMatch("a").Should().Be(1.0d); score.Should().Be(1.0d);
} }
[Fact] [Fact]
@@ -39,11 +41,13 @@ public class WildcardMatcherTest
Pattern = "b" Pattern = "b"
}; };
// Act
var matcher = new WildcardMatcher(new [] { pattern1, pattern2 }); var matcher = new WildcardMatcher(new [] { pattern1, pattern2 });
// Act
var score = matcher.IsMatch("a").Score;
// Assert // Assert
matcher.IsMatch("a").Should().Be(1.0d); score.Should().Be(1.0d);
} }
[Fact] [Fact]
@@ -69,7 +73,12 @@ public class WildcardMatcherTest
foreach (var test in tests) foreach (var test in tests)
{ {
var matcher = new WildcardMatcher(test.p); var matcher = new WildcardMatcher(test.p);
matcher.IsMatch(test.i).Should().Be(1.0d, $"Pattern '{test.p}' with value '{test.i}' should be 1.0");
// Act
var score = matcher.IsMatch(test.i).Score;
// Assert
score.Should().Be(MatchScores.Perfect, $"Pattern '{test.p}' with value '{test.i}' should be 1.0");
} }
} }
@@ -94,7 +103,12 @@ public class WildcardMatcherTest
foreach (var test in tests) foreach (var test in tests)
{ {
var matcher = new WildcardMatcher(test.p); var matcher = new WildcardMatcher(test.p);
Check.That(matcher.IsMatch(test.i)).IsEqualTo(0.0);
// Act
var score = matcher.IsMatch(test.i).Score;
// Assert
score.Should().Be(MatchScores.Mismatch);
} }
} }
@@ -105,7 +119,7 @@ public class WildcardMatcherTest
var matcher = new WildcardMatcher("x"); var matcher = new WildcardMatcher("x");
// Act // Act
string name = matcher.Name; var name = matcher.Name;
// Assert // Assert
Check.That(name).Equals("WildcardMatcher"); Check.That(name).Equals("WildcardMatcher");
@@ -131,7 +145,7 @@ public class WildcardMatcherTest
var matcher = new WildcardMatcher(MatchBehaviour.RejectOnMatch, "m"); var matcher = new WildcardMatcher(MatchBehaviour.RejectOnMatch, "m");
// Act // Act
double result = matcher.IsMatch("m"); var result = matcher.IsMatch("m").Score;
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
} }
@@ -43,7 +43,7 @@ public class XPathMatcherTests
var matcher = new XPathMatcher("/todo-list[count(todo-item) = 1]"); var matcher = new XPathMatcher("/todo-list[count(todo-item) = 1]");
// Act // Act
double result = matcher.IsMatch(xml); double result = matcher.IsMatch(xml).Score;
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
@@ -57,10 +57,10 @@ public class XPathMatcherTests
<todo-list> <todo-list>
<todo-item id='a1'>abc</todo-item> <todo-item id='a1'>abc</todo-item>
</todo-list>"; </todo-list>";
var matcher = new XPathMatcher(MatchBehaviour.RejectOnMatch, false, MatchOperator.Or, "/todo-list[count(todo-item) = 1]"); var matcher = new XPathMatcher(MatchBehaviour.RejectOnMatch, MatchOperator.Or, "/todo-list[count(todo-item) = 1]");
// Act // Act
double result = matcher.IsMatch(xml); double result = matcher.IsMatch(xml).Score;
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Xunit; using Xunit;
using Moq; using Moq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading; using System.Threading;
using FluentAssertions;
using WireMock.Handlers; using WireMock.Handlers;
using WireMock.Owin.Mappers; using WireMock.Owin.Mappers;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
@@ -235,6 +237,24 @@ namespace WireMock.Net.Tests.Owin.Mappers
#endif #endif
} }
[Fact]
public void OwinResponseMapper_MapAsync_BodyAsFile_ThrowsException()
{
// Arrange
var responseMessage = new ResponseMessage
{
Headers = new Dictionary<string, WireMockList<string>>(),
BodyData = new BodyData { DetectedBodyType = BodyType.File, BodyAsFile = string.Empty }
};
_fileSystemHandlerMock.Setup(f => f.ReadResponseBodyAsFile(It.IsAny<string>())).Throws<FileNotFoundException>();
// Act
Func<Task> action = () => _sut.MapAsync(responseMessage, _responseMock.Object);
// Assert
action.Should().ThrowAsync<FileNotFoundException>();
}
[Fact] [Fact]
public async Task OwinResponseMapper_MapAsync_WithFault_EMPTY_RESPONSE() public async Task OwinResponseMapper_MapAsync_WithFault_EMPTY_RESPONSE()
{ {
@@ -251,7 +271,7 @@ namespace WireMock.Net.Tests.Owin.Mappers
await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false); await _sut.MapAsync(responseMessage, _responseMock.Object).ConfigureAwait(false);
// Assert // Assert
_stream.Verify(s => s.WriteAsync(new byte[0], 0, 0, It.IsAny<CancellationToken>()), Times.Once); _stream.Verify(s => s.WriteAsync(EmptyArray<byte>.Value, 0, 0, It.IsAny<CancellationToken>()), Times.Once);
} }
[Theory] [Theory]
@@ -220,7 +220,7 @@ public class MappingMatcherTests
var requestMatchResult = new RequestMatchResult(); var requestMatchResult = new RequestMatchResult();
foreach (var score in match.scores) foreach (var score in match.scores)
{ {
requestMatchResult.AddScore(typeof(object), score); requestMatchResult.AddScore(typeof(object), score, null);
} }
mappingMock.SetupGet(m => m.Probability).Returns(match.probability); mappingMock.SetupGet(m => m.Probability).Returns(match.probability);
@@ -15,8 +15,8 @@ namespace WireMock.Net.Tests.Serialization;
public class CustomPathParamMatcher : IStringMatcher public class CustomPathParamMatcher : IStringMatcher
{ {
public string Name => nameof(CustomPathParamMatcher); public string Name => nameof(CustomPathParamMatcher);
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
public bool ThrowException { get; }
private readonly string _path; private readonly string _path;
private readonly string[] _pathParts; private readonly string[] _pathParts;
@@ -30,18 +30,16 @@ public class CustomPathParamMatcher : IStringMatcher
MatchBehaviour matchBehaviour, MatchBehaviour matchBehaviour,
string path, string path,
Dictionary<string, string> pathParams, Dictionary<string, string> pathParams,
bool throwException = false,
MatchOperator matchOperator = MatchOperator.Or) MatchOperator matchOperator = MatchOperator.Or)
{ {
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_path = path; _path = path;
_pathParts = GetPathParts(path); _pathParts = GetPathParts(path);
_pathParams = pathParams.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase); _pathParams = pathParams.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
MatchOperator = matchOperator; MatchOperator = matchOperator;
} }
public double IsMatch(string? input) public MatchResult IsMatch(string? input)
{ {
var inputParts = GetPathParts(input); var inputParts = GetPathParts(input);
if (inputParts.Length != _pathParts.Length) if (inputParts.Length != _pathParts.Length)
@@ -79,11 +77,6 @@ public class CustomPathParamMatcher : IStringMatcher
} }
catch catch
{ {
if (ThrowException)
{
throw;
}
return MatchScores.Mismatch; return MatchScores.Mismatch;
} }
@@ -43,14 +43,14 @@ public class MatcherModelMapperTests
// Assert 1 // Assert 1
matcher1.Should().NotBeNull(); matcher1.Should().NotBeNull();
matcher1.IsMatch("x").Should().Be(1.0d); matcher1.IsMatch("x").Score.Should().Be(1.0d);
// Act 2 // Act 2
var matcher2 = (ICSharpCodeMatcher)sut.Map(model)!; var matcher2 = (ICSharpCodeMatcher)sut.Map(model)!;
// Assert 2 // Assert 2
matcher2.Should().NotBeNull(); matcher2.Should().NotBeNull();
matcher2.IsMatch("x").Should().Be(1.0d); matcher2.IsMatch("x").Score.Should().Be(1.0d);
} }
[Fact] [Fact]
@@ -96,7 +96,6 @@ public class MatcherModelMapperTests
// Assert // Assert
matcher.GetPatterns().Should().ContainSingle("x"); matcher.GetPatterns().Should().ContainSingle("x");
matcher.ThrowException.Should().BeFalse();
} }
[Fact] [Fact]
@@ -136,7 +135,6 @@ public class MatcherModelMapperTests
matcher.IgnoreCase.Should().BeFalse(); matcher.IgnoreCase.Should().BeFalse();
matcher.Value.Should().Be(pattern); matcher.Value.Should().Be(pattern);
matcher.Regex.Should().BeFalse(); matcher.Regex.Should().BeFalse();
matcher.ThrowException.Should().BeFalse();
} }
[Fact] [Fact]
@@ -159,43 +157,6 @@ public class MatcherModelMapperTests
matcher.IgnoreCase.Should().BeFalse(); matcher.IgnoreCase.Should().BeFalse();
matcher.Value.Should().Be(pattern); matcher.Value.Should().Be(pattern);
matcher.Regex.Should().BeTrue(); matcher.Regex.Should().BeTrue();
matcher.ThrowException.Should().BeFalse();
}
[Theory]
[InlineData(nameof(LinqMatcher))]
[InlineData(nameof(ExactMatcher))]
[InlineData(nameof(ExactObjectMatcher))]
[InlineData(nameof(RegexMatcher))]
[InlineData(nameof(JsonMatcher))]
[InlineData(nameof(JsonPartialMatcher))]
[InlineData(nameof(JsonPartialWildcardMatcher))]
[InlineData(nameof(JsonPathMatcher))]
[InlineData(nameof(JmesPathMatcher))]
[InlineData(nameof(XPathMatcher))]
[InlineData(nameof(WildcardMatcher))]
[InlineData(nameof(ContentTypeMatcher))]
[InlineData(nameof(SimMetricsMatcher))]
public void MatcherModelMapper_Map_ThrowExceptionWhenMatcherFails_True(string name)
{
// Assign
var settings = new WireMockServerSettings
{
ThrowExceptionWhenMatcherFails = true
};
var sut = new MatcherMapper(settings);
var model = new MatcherModel
{
Name = name,
Patterns = new[] { "" }
};
// Act
var matcher = sut.Map(model)!;
// Assert
matcher.Should().NotBeNull();
matcher.ThrowException.Should().BeTrue();
} }
[Fact] [Fact]
@@ -249,7 +210,9 @@ public class MatcherModelMapperTests
// Assert // Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y"); Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
Check.That(matcher.IsMatch("X")).IsEqualTo(expected);
var result = matcher.IsMatch("X");
result.Score.Should().Be(expected);
} }
[Theory] [Theory]
@@ -272,7 +235,9 @@ public class MatcherModelMapperTests
// Assert // Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y"); Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
Check.That(matcher.IsMatch("X")).IsEqualTo(expected);
var result = matcher.IsMatch("X");
result.Score.Should().Be(expected);
} }
[Fact] [Fact]
@@ -306,7 +271,9 @@ public class MatcherModelMapperTests
// Assert // Assert
matcher.GetPatterns().Should().HaveCount(1).And.Contain(new AnyOf<string, StringPattern>(stringPattern)); matcher.GetPatterns().Should().HaveCount(1).And.Contain(new AnyOf<string, StringPattern>(stringPattern));
matcher.IsMatch("c").Should().Be(1.0d);
var result = matcher.IsMatch("c");
result.Score.Should().Be(MatchScores.Perfect);
} }
[Fact] [Fact]
@@ -395,8 +362,7 @@ public class MatcherModelMapperTests
return new CustomPathParamMatcher( return new CustomPathParamMatcher(
matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch, matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
matcherParams.Path, matcherParams.Path,
matcherParams.PathParams, matcherParams.PathParams
settings.ThrowExceptionWhenMatcherFails == true
); );
}; };
var sut = new MatcherMapper(settings); var sut = new MatcherMapper(settings);
@@ -77,7 +77,6 @@ server
.WithBody(new JsonPartialMatcher( .WithBody(new JsonPartialMatcher(
value: "{ a = 1, b = 2 }", value: "{ a = 1, b = 2 }",
ignoreCase: false, ignoreCase: false,
throwException: false,
regex: false regex: false
)) ))
) )
+42 -44
View File
@@ -138,25 +138,25 @@ public partial class WireMockServerTests
#if NETCOREAPP3_1 || NET5_0 || NET6_0 || NET7_0 #if NETCOREAPP3_1 || NET5_0 || NET6_0 || NET7_0
[Fact] [Fact]
public async Task WireMockServer_WithCorsPolicyOptions_Should_Work_Correct() public async Task WireMockServer_WithCorsPolicyOptions_Should_Work_Correct()
{
// Arrange
var settings = new WireMockServerSettings
{ {
CorsPolicyOptions = CorsPolicyOptions.AllowAll // Arrange
}; var settings = new WireMockServerSettings
var server = WireMockServer.Start(settings); {
CorsPolicyOptions = CorsPolicyOptions.AllowAll
};
var server = WireMockServer.Start(settings);
server.Given(Request.Create().WithPath("/*")).RespondWith(Response.Create().WithBody("x")); server.Given(Request.Create().WithPath("/*")).RespondWith(Response.Create().WithBody("x"));
// Act // Act
var response = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/foo").ConfigureAwait(false); var response = await new HttpClient().GetStringAsync("http://localhost:" + server.Ports[0] + "/foo").ConfigureAwait(false);
// Asser. // Asser.
response.Should().Be("x"); response.Should().Be("x");
server.Stop(); server.Stop();
} }
#endif #endif
[Fact] [Fact]
@@ -277,34 +277,34 @@ public async Task WireMockServer_WithCorsPolicyOptions_Should_Work_Correct()
} }
#if !NET452 && !NET461 #if !NET452 && !NET461
[Theory] [Theory]
[InlineData("TRACE")] [InlineData("TRACE")]
[InlineData("GET")] [InlineData("GET")]
public async Task WireMockServer_Should_exclude_body_for_methods_where_body_is_definitely_disallowed(string method) public async Task WireMockServer_Should_exclude_body_for_methods_where_body_is_definitely_disallowed(string method)
{ {
// Assign // Assign
string content = "hello"; string content = "hello";
var server = WireMockServer.Start(); var server = WireMockServer.Start();
server server
.Given(Request.Create().WithBody((byte[] bodyBytes) => bodyBytes != null)) .Given(Request.Create().WithBody((byte[] bodyBytes) => bodyBytes != null))
.AtPriority(0) .AtPriority(0)
.RespondWith(Response.Create().WithStatusCode(400)); .RespondWith(Response.Create().WithStatusCode(400));
server server
.Given(Request.Create()) .Given(Request.Create())
.AtPriority(1) .AtPriority(1)
.RespondWith(Response.Create().WithStatusCode(200)); .RespondWith(Response.Create().WithStatusCode(200));
// Act // Act
var request = new HttpRequestMessage(new HttpMethod(method), "http://localhost:" + server.Ports[0] + "/"); var request = new HttpRequestMessage(new HttpMethod(method), "http://localhost:" + server.Ports[0] + "/");
request.Content = new StringContent(content); request.Content = new StringContent(content);
var response = await new HttpClient().SendAsync(request).ConfigureAwait(false); var response = await new HttpClient().SendAsync(request).ConfigureAwait(false);
// Assert // Assert
Check.That(response.StatusCode).Equals(HttpStatusCode.OK); Check.That(response.StatusCode).Equals(HttpStatusCode.OK);
server.Stop(); server.Stop();
} }
#endif #endif
[Theory] [Theory]
@@ -462,11 +462,10 @@ public async Task WireMockServer_Should_exclude_body_for_methods_where_body_is_d
settings.CustomMatcherMappings = new Dictionary<string, Func<MatcherModel, IMatcher>>(); settings.CustomMatcherMappings = new Dictionary<string, Func<MatcherModel, IMatcher>>();
settings.CustomMatcherMappings[nameof(CustomPathParamMatcher)] = matcherModel => settings.CustomMatcherMappings[nameof(CustomPathParamMatcher)] = matcherModel =>
{ {
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)matcherModel.Pattern); var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)matcherModel.Pattern!)!;
return new CustomPathParamMatcher( return new CustomPathParamMatcher(
matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch, matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
matcherParams.Path, matcherParams.PathParams, matcherParams.Path, matcherParams.PathParams
settings.ThrowExceptionWhenMatcherFails == true
); );
}; };
@@ -510,11 +509,10 @@ public async Task WireMockServer_Should_exclude_body_for_methods_where_body_is_d
settings.CustomMatcherMappings = new Dictionary<string, Func<MatcherModel, IMatcher>>(); settings.CustomMatcherMappings = new Dictionary<string, Func<MatcherModel, IMatcher>>();
settings.CustomMatcherMappings[nameof(CustomPathParamMatcher)] = matcherModel => settings.CustomMatcherMappings[nameof(CustomPathParamMatcher)] = matcherModel =>
{ {
var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)matcherModel.Pattern); var matcherParams = JsonConvert.DeserializeObject<CustomPathParamMatcherModel>((string)matcherModel.Pattern!)!;
return new CustomPathParamMatcher( return new CustomPathParamMatcher(
matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch, matcherModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
matcherParams.Path, matcherParams.PathParams, matcherParams.Path, matcherParams.PathParams
settings.ThrowExceptionWhenMatcherFails == true
); );
}; };