Create WireMock.Net.MimePart project (#1300)

* Create WireMock.Net.MimePart project

* .

* REFACTOR

* ILRepack

* --

* ...

* x

* x

* .

* fix

* public class MimePartMatcher

* shared

* min

* .

* <!--<DelaySign>true</DelaySign>-->

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Stef Heyenrath
2025-05-24 12:17:42 +02:00
committed by GitHub
parent c15206ecd8
commit 96eca4262a
306 changed files with 9746 additions and 9285 deletions

View File

@@ -0,0 +1,82 @@
// Copyright © WireMock.Net
using System.Linq;
using Stef.Validation;
namespace WireMock.Matchers;
/// <summary>
/// ExactObjectMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public class ExactObjectMatcher : IObjectMatcher
{
/// <inheritdoc />
public object Value { get; }
/// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher(object value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, object value)
{
Value = Guard.NotNull(value);
MatchBehaviour = matchBehaviour;
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="value">The value.</param>
public ExactObjectMatcher(byte[] value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, byte[] value)
{
Value = Guard.NotNull(value);
MatchBehaviour = matchBehaviour;
}
/// <inheritdoc />
public MatchResult IsMatch(object? input)
{
bool equals;
if (Value is byte[] valueAsBytes && input is byte[] inputAsBytes)
{
equals = valueAsBytes.SequenceEqual(inputAsBytes);
}
else
{
equals = Equals(Value, input);
}
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
}
/// <inheritdoc />
public string Name => nameof(ExactObjectMatcher);
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return "NotImplemented";
}
}

View File

@@ -0,0 +1,77 @@
// Copyright © WireMock.Net
using Stef.Validation;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.Matchers.Helpers;
internal static class BodyDataMatchScoreCalculator
{
internal static MatchResult CalculateMatchScore(IBodyData? requestMessage, IMatcher matcher)
{
Guard.NotNull(matcher);
if (requestMessage == null)
{
return default;
}
if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
{
switch (requestMessage.DetectedBodyType)
{
case BodyType.Json:
case BodyType.String:
case BodyType.FormUrlEncoded:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsString);
case BodyType.Bytes:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsBytes);
default:
return default;
}
}
if (matcher is ExactObjectMatcher exactObjectMatcher)
{
// If the body is a byte array, try to match.
var detectedBodyType = requestMessage.DetectedBodyType;
if (detectedBodyType is BodyType.Bytes or BodyType.String or BodyType.FormUrlEncoded)
{
return exactObjectMatcher.IsMatch(requestMessage.BodyAsBytes);
}
}
// Check if the matcher is a IObjectMatcher
if (matcher is IObjectMatcher objectMatcher)
{
// If the body is a JSON object, try to match.
if (requestMessage.DetectedBodyType == BodyType.Json)
{
return objectMatcher.IsMatch(requestMessage.BodyAsJson);
}
// If the body is a byte array, try to match.
if (requestMessage.DetectedBodyType == BodyType.Bytes)
{
return objectMatcher.IsMatch(requestMessage.BodyAsBytes);
}
}
// In case the matcher is a IStringMatcher and If body is a Json or a String, use the BodyAsString to match on.
if (matcher is IStringMatcher stringMatcher && requestMessage.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
{
return stringMatcher.IsMatch(requestMessage.BodyAsString);
}
// In case the matcher is a IProtoBufMatcher, use the BodyAsBytes to match on.
if (matcher is IProtoBufMatcher protoBufMatcher)
{
return protoBufMatcher.IsMatchAsync(requestMessage.BodyAsBytes).GetAwaiter().GetResult();
}
return default;
}
}

View File

@@ -0,0 +1,20 @@
// Copyright © WireMock.Net
using System.Threading;
using System.Threading.Tasks;
namespace WireMock.Matchers;
/// <summary>
/// IBytesMatcher
/// </summary>
public interface IBytesMatcher : IMatcher
{
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input byte array.</param>
/// <param name="cancellationToken">The CancellationToken [optional].</param>
/// <returns>MatchResult</returns>
Task<MatchResult> IsMatchAsync(byte[]? input, CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,12 @@
// Copyright © WireMock.Net
namespace WireMock.Matchers;
/// <summary>
/// CSharpCode / CS-Script Matcher
/// </summary>
/// <inheritdoc cref="IObjectMatcher"/>
/// <inheritdoc cref="IStringMatcher"/>
public interface ICSharpCodeMatcher : IObjectMatcher, IStringMatcher
{
}

View File

@@ -0,0 +1,20 @@
// Copyright © WireMock.Net
using System.Threading;
using System.Threading.Tasks;
namespace WireMock.Matchers;
/// <summary>
/// IDecodeBytesMatcher
/// </summary>
public interface IDecodeBytesMatcher
{
/// <summary>
/// Decode byte array to an object.
/// </summary>
/// <param name="input">The byte array</param>
/// <param name="cancellationToken">The CancellationToken [optional].</param>
/// <returns>object</returns>
Task<object?> DecodeAsync(byte[]? input, CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,15 @@
// Copyright © WireMock.Net
namespace WireMock.Matchers;
/// <summary>
/// IIgnoreCaseMatcher
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IIgnoreCaseMatcher : IMatcher
{
/// <summary>
/// Ignore the case from the pattern.
/// </summary>
bool IgnoreCase { get; }
}

View File

@@ -0,0 +1,25 @@
// Copyright © WireMock.Net
namespace WireMock.Matchers;
/// <summary>
/// IMatcher
/// </summary>
public interface IMatcher
{
/// <summary>
/// Gets the name.
/// </summary>
string Name { get; }
/// <summary>
/// Gets the match behaviour.
/// </summary>
MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Get the C# code arguments.
/// </summary>
/// <returns></returns>
string GetCSharpCodeArguments();
}

View File

@@ -0,0 +1,37 @@
// Copyright © WireMock.Net
namespace WireMock.Matchers;
/// <summary>
/// MimePartMatcher
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IMimePartMatcher : IMatcher
{
/// <summary>
/// ContentType Matcher (image/png; name=image.png.)
/// </summary>
IStringMatcher? ContentTypeMatcher { get; }
/// <summary>
/// ContentDisposition Matcher (attachment; filename=image.png)
/// </summary>
IStringMatcher? ContentDispositionMatcher { get; }
/// <summary>
/// ContentTransferEncoding Matcher (base64)
/// </summary>
IStringMatcher? ContentTransferEncodingMatcher { get; }
/// <summary>
/// Content Matcher
/// </summary>
IMatcher? ContentMatcher { get; }
/// <summary>
/// Determines whether the specified MimePart is match.
/// </summary>
/// <param name="value">The MimePart.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
public MatchResult IsMatch(object value);
}

View File

@@ -0,0 +1,22 @@
// Copyright © WireMock.Net
namespace WireMock.Matchers;
/// <summary>
/// IObjectMatcher
/// </summary>
public interface IObjectMatcher : IMatcher
{
/// <summary>
/// Gets the value (can be a string or an object).
/// </summary>
/// <returns>Value</returns>
object Value { get; }
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>MatchResult</returns>
MatchResult IsMatch(object? input);
}

View File

@@ -0,0 +1,10 @@
// Copyright © WireMock.Net
namespace WireMock.Matchers;
/// <summary>
/// IProtoBufMatcher
/// </summary>
public interface IProtoBufMatcher : IDecodeBytesMatcher, IBytesMatcher
{
}

View File

@@ -0,0 +1,31 @@
// Copyright © WireMock.Net
using AnyOfTypes;
using WireMock.Models;
namespace WireMock.Matchers;
/// <summary>
/// IStringMatcher
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IStringMatcher : IMatcher
{
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>MatchResult</returns>
MatchResult IsMatch(string? input);
/// <summary>
/// Gets the patterns.
/// </summary>
/// <returns>Patterns</returns>
AnyOf<string, StringPattern>[] GetPatterns();
/// <summary>
/// The <see cref="Matchers.MatchOperator"/>.
/// </summary>
MatchOperator MatchOperator { get; }
}

View File

@@ -0,0 +1,19 @@
// Copyright © WireMock.Net
namespace WireMock.Matchers;
/// <summary>
/// MatchBehaviour (Accept or Reject)
/// </summary>
public enum MatchBehaviour
{
/// <summary>
/// Accept on match (default)
/// </summary>
AcceptOnMatch,
/// <summary>
/// Reject on match
/// </summary>
RejectOnMatch
}

View File

@@ -0,0 +1,41 @@
// Copyright © WireMock.Net
namespace WireMock.Matchers;
/// <summary>
/// MatchBehaviourHelper
/// </summary>
internal static class MatchBehaviourHelper
{
/// <summary>
/// Converts the specified match behaviour and match value to a new match value.
///
/// if AcceptOnMatch --> return match (default)
/// if RejectOnMatch and match = 0.0 --> return 1.0
/// if RejectOnMatch and match = 0.? --> return 0.0
/// if RejectOnMatch and match = 1.0 --> return 0.0
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="match">The match.</param>
/// <returns>match value</returns>
internal static double Convert(MatchBehaviour matchBehaviour, double match)
{
if (matchBehaviour == MatchBehaviour.AcceptOnMatch)
{
return match;
}
return match <= MatchScores.Tolerance ? MatchScores.Perfect : MatchScores.Mismatch;
}
/// <summary>
/// Converts the specified match behaviour and match result to a new match result value.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="result">The match result.</param>
/// <returns>match result</returns>
internal static MatchResult Convert(MatchBehaviour matchBehaviour, MatchResult result)
{
return matchBehaviour == MatchBehaviour.AcceptOnMatch ? result : new MatchResult(Convert(matchBehaviour, result.Score), result.Exception);
}
}

View File

@@ -0,0 +1,24 @@
// Copyright © WireMock.Net
namespace WireMock.Matchers;
/// <summary>
/// The Operator to use when multiple patterns are defined.
/// </summary>
public enum MatchOperator
{
/// <summary>
/// Only one pattern needs to match. [Default]
/// </summary>
Or,
/// <summary>
/// All patterns should match.
/// </summary>
And,
/// <summary>
/// The average value from all patterns.
/// </summary>
Average
}

View File

@@ -0,0 +1,91 @@
// Copyright © WireMock.Net
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);
}
}

View File

@@ -0,0 +1,85 @@
// Copyright © WireMock.Net
using System;
using System.Collections.Generic;
using System.Linq;
namespace WireMock.Matchers;
/// <summary>
/// MatchScores
/// </summary>
public static class MatchScores
{
/// <summary>
/// The tolerance
/// </summary>
public const double Tolerance = 0.000001;
/// <summary>
/// The default mismatch score
/// </summary>
public const double Mismatch = 0.0;
/// <summary>
/// The default perfect match score
/// </summary>
public const double Perfect = 1.0;
/// <summary>
/// The almost perfect match score
/// </summary>
public const double AlmostPerfect = 0.99;
/// <summary>
/// Is the value a perfect match?
/// </summary>
/// <param name="value">The value.</param>
/// <returns>true/false</returns>
public static bool IsPerfect(double value)
{
return Math.Abs(value - Perfect) < Tolerance;
}
/// <summary>
/// Convert a bool to the score.
/// </summary>
/// <param name="value">if set to <c>true</c> [value].</param>
/// <returns>score</returns>
public static double ToScore(bool value)
{
return value ? Perfect : Mismatch;
}
/// <summary>
/// Calculates the score from multiple values.
/// </summary>
/// <param name="values">The values.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/>.</param>
/// <returns>average score</returns>
public static double ToScore(IReadOnlyCollection<bool> values, MatchOperator matchOperator)
{
return ToScore(values.Select(ToScore).ToArray(), matchOperator);
}
/// <summary>
/// Calculates the score from multiple values.
/// </summary>
/// <param name="values">The values.</param>
/// <param name="matchOperator"></param>
/// <returns>average score</returns>
public static double ToScore(IReadOnlyCollection<double> values, MatchOperator matchOperator)
{
if (!values.Any())
{
return Mismatch;
}
return matchOperator switch
{
MatchOperator.Or => ToScore(values.Any(IsPerfect)),
MatchOperator.And => ToScore(values.All(IsPerfect)),
_ => values.Average()
};
}
}

View File

@@ -0,0 +1,84 @@
// Copyright © WireMock.Net
using System;
using System.Linq;
using AnyOfTypes;
using WireMock.Extensions;
using WireMock.Models;
namespace WireMock.Matchers;
/// <summary>
/// NotNullOrEmptyMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public class NotNullOrEmptyMatcher : IObjectMatcher, IStringMatcher
{
/// <inheritdoc />
public string Name => nameof(NotNullOrEmptyMatcher);
/// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc />
public object Value { get; }
/// <summary>
/// Initializes a new instance of the <see cref="NotNullOrEmptyMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
public NotNullOrEmptyMatcher(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
{
MatchBehaviour = matchBehaviour;
Value = string.Empty;
}
/// <inheritdoc />
public MatchResult IsMatch(object? input)
{
bool match;
switch (input)
{
case string @string:
match = !string.IsNullOrEmpty(@string);
break;
case byte[] bytes:
match = bytes.Any();
break;
default:
match = input != null;
break;
}
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
/// <inheritdoc />
public MatchResult IsMatch(string? input)
{
var match = !string.IsNullOrEmpty(input);
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
/// <inheritdoc />
public AnyOf<string, StringPattern>[] GetPatterns()
{
return [];
}
/// <inheritdoc />
public MatchOperator MatchOperator => MatchOperator.Or;
/// <inheritdoc />
public string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}" +
$")";
}
}

View File

@@ -0,0 +1,144 @@
// Copyright © WireMock.Net
using System;
using System.Linq;
using System.Text.RegularExpressions;
using AnyOfTypes;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Constants;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.RegularExpressions;
using WireMock.Util;
namespace WireMock.Matchers;
/// <summary>
/// Regular Expression Matcher
/// </summary>
/// <inheritdoc cref="IStringMatcher"/>
/// <inheritdoc cref="IIgnoreCaseMatcher"/>
public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
{
private readonly AnyOf<string, StringPattern>[] _patterns;
private readonly Regex[] _expressions;
private readonly bool _useRegexExtended;
/// <inheritdoc />
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RegexMatcher"/> class.
/// </summary>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="useRegexExtended">Use RegexExtended (default = true).</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
public RegexMatcher(
[RegexPattern] AnyOf<string, StringPattern> pattern,
bool ignoreCase = false,
bool useRegexExtended = true,
MatchOperator matchOperator = MatchOperator.Or) :
this(MatchBehaviour.AcceptOnMatch, [pattern], ignoreCase, useRegexExtended, matchOperator)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RegexMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="useRegexExtended">Use RegexExtended (default = true).</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
public RegexMatcher(
MatchBehaviour matchBehaviour,
[RegexPattern] AnyOf<string, StringPattern> pattern,
bool ignoreCase = false,
bool useRegexExtended = true,
MatchOperator matchOperator = MatchOperator.Or) :
this(matchBehaviour, [pattern], ignoreCase, useRegexExtended, matchOperator)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RegexMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="useRegexExtended">Use RegexExtended (default = true).</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
public RegexMatcher(
MatchBehaviour matchBehaviour,
[RegexPattern] AnyOf<string, StringPattern>[] patterns,
bool ignoreCase = false,
bool useRegexExtended = true,
MatchOperator matchOperator = MatchOperator.Or)
{
_patterns = Guard.NotNull(patterns);
IgnoreCase = ignoreCase;
_useRegexExtended = useRegexExtended;
MatchBehaviour = matchBehaviour;
MatchOperator = matchOperator;
var options = RegexOptions.Compiled | RegexOptions.Multiline;
if (ignoreCase)
{
options |= RegexOptions.IgnoreCase;
}
_expressions = patterns.Select(p => useRegexExtended ? new RegexExtended(p.GetPattern(), options) : new Regex(p.GetPattern(), options, RegexConstants.DefaultTimeout)).ToArray();
}
/// <inheritdoc />
public virtual MatchResult IsMatch(string? input)
{
var score = MatchScores.Mismatch;
Exception? exception = null;
if (input != null)
{
try
{
score = MatchScores.ToScore(_expressions.Select(e => e.IsMatch(input)).ToArray(), MatchOperator);
}
catch (Exception ex)
{
exception = ex;
}
}
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
}
/// <inheritdoc />
public virtual AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc />
public virtual string Name => nameof(RegexMatcher);
/// <inheritdoc />
public bool IgnoreCase { get; }
/// <inheritdoc />
public MatchOperator MatchOperator { get; }
/// <inheritdoc />
public virtual string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(_useRegexExtended)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
}

View File

@@ -0,0 +1,97 @@
// Copyright © WireMock.Net
using System.Linq;
using System.Text.RegularExpressions;
using AnyOfTypes;
using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.Util;
namespace WireMock.Matchers;
/// <summary>
/// WildcardMatcher
/// </summary>
/// <seealso cref="RegexMatcher" />
public class WildcardMatcher : RegexMatcher
{
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <summary>
/// Initializes a new instance of the <see cref="WildcardMatcher"/> class.
/// </summary>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase</param>
public WildcardMatcher(AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WildcardMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase</param>
public WildcardMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WildcardMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase</param>
public WildcardMatcher(AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WildcardMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
public WildcardMatcher(
MatchBehaviour matchBehaviour,
AnyOf<string, StringPattern>[] patterns,
bool ignoreCase = false,
MatchOperator matchOperator = MatchOperator.Or) : base(matchBehaviour, CreateArray(patterns), ignoreCase, true, matchOperator)
{
_patterns = Guard.NotNull(patterns);
}
/// <inheritdoc />
public override AnyOf<string, StringPattern>[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc />
public override string Name => nameof(WildcardMatcher);
/// <inheritdoc />
public override string GetCSharpCodeArguments()
{
return $"new {Name}" +
$"(" +
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
$")";
}
private static AnyOf<string, StringPattern>[] CreateArray(AnyOf<string, StringPattern>[] patterns)
{
return patterns
.Select(pattern => new AnyOf<string, StringPattern>(
new StringPattern
{
Pattern = "^" + Regex.Escape(pattern.GetPattern()).Replace(@"\*", ".*").Replace(@"\?", ".") + "$",
PatternAsFile = pattern.IsSecond ? pattern.Second.PatternAsFile : null
}))
.ToArray();
}
}