RegexExtended in settings (#700)

* Add extra unittest for RegexExtended

* settings
This commit is contained in:
Stef Heyenrath
2021-12-12 15:40:38 +01:00
committed by GitHub
parent 4a434b5dba
commit 6943b90da6
8 changed files with 71 additions and 24 deletions

View File

@@ -18,7 +18,7 @@ namespace WireMock.Matchers
public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
{
private readonly AnyOf<string, StringPattern>[] _patterns;
private readonly RegexExtended[] _expressions;
private readonly Regex[] _expressions;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
@@ -31,7 +31,10 @@ namespace WireMock.Matchers
/// </summary>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RegexMatcher([NotNull, RegexPattern] AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="useRegexExtended">Use RegexExtended (default = true).</param>
public RegexMatcher([NotNull, RegexPattern] AnyOf<string, StringPattern> pattern, bool ignoreCase = false, bool throwException = false, bool useRegexExtended = true) :
this(MatchBehaviour.AcceptOnMatch, new[] { pattern }, ignoreCase, throwException, useRegexExtended)
{
}
@@ -41,16 +44,10 @@ namespace WireMock.Matchers
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RegexMatcher(MatchBehaviour matchBehaviour, [NotNull, RegexPattern] AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RegexMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RegexMatcher([NotNull, RegexPattern] AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="useRegexExtended">Use RegexExtended (default = true).</param>
public RegexMatcher(MatchBehaviour matchBehaviour, [NotNull, RegexPattern] AnyOf<string, StringPattern> pattern, bool ignoreCase = false, bool throwException = false, bool useRegexExtended = true) :
this(matchBehaviour, new[] { pattern }, ignoreCase, throwException, useRegexExtended)
{
}
@@ -61,7 +58,8 @@ namespace WireMock.Matchers
/// <param name="patterns">The patterns.</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>
public RegexMatcher(MatchBehaviour matchBehaviour, [NotNull, RegexPattern] AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false, bool throwException = false)
/// <param name="useRegexExtended">Use RegexExtended (default = true).</param>
public RegexMatcher(MatchBehaviour matchBehaviour, [NotNull, RegexPattern] AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false, bool throwException = false, bool useRegexExtended = true)
{
Check.NotNull(patterns, nameof(patterns));
@@ -77,7 +75,7 @@ namespace WireMock.Matchers
options |= RegexOptions.IgnoreCase;
}
_expressions = patterns.Select(p => new RegexExtended(p.GetPattern(), options)).ToArray();
_expressions = patterns.Select(p => useRegexExtended ? new RegexExtended(p.GetPattern(), options) : new Regex(p.GetPattern(), options)).ToArray();
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>

View File

@@ -16,16 +16,13 @@ namespace WireMock.RegularExpressions
}
/// <inheritdoc cref="Regex"/>
public RegexExtended(string pattern,
RegexOptions options)
public RegexExtended(string pattern, RegexOptions options)
: this(pattern, options, Regex.InfiniteMatchTimeout)
{
}
/// <inheritdoc cref="Regex"/>
public RegexExtended(string pattern,
RegexOptions options,
TimeSpan matchTimeout)
public RegexExtended(string pattern, RegexOptions options, TimeSpan matchTimeout)
: base(ReplaceGuidPattern(pattern), options, matchTimeout)
{
}
@@ -35,22 +32,31 @@ namespace WireMock.RegularExpressions
{
// Lower case format `B` Guid pattern
{ @"\guidb", @"(\{[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}\})" },
// Upper case format `B` Guid pattern
{ @"\GUIDB", @"(\{[A-Z0-9]{8}-([A-Z0-9]{4}-){3}[A-Z0-9]{12}\})" },
// Lower case format `D` Guid pattern
{ @"\guidd", "([a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12})" },
// Upper case format `D` Guid pattern
{ @"\GUIDD", "([A-Z0-9]{8}-([A-Z0-9]{4}-){3}[A-Z0-9]{12})" },
// Lower case format `N` Guid pattern
{ @"\guidn", "([a-z0-9]{32})" },
// Upper case format `N` Guid pattern
{ @"\GUIDN", "([A-Z0-9]{32})" },
// Lower case format `P` Guid pattern
{ @"\guidp", @"(\([a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}\))" },
// Upper case format `P` Guid pattern
{ @"\GUIDP", @"(\([A-Z0-9]{8}-([A-Z0-9]{4}-){3}[A-Z0-9]{12}\))" },
// Lower case format `X` Guid pattern
{ @"\guidx", @"(\{0x[a-f0-9]{8},0x[a-f0-9]{4},0x[a-f0-9]{4},\{(0x[a-f0-9]{2},){7}(0x[a-f0-9]{2})\}\})" },
// Upper case format `X` Guid pattern
{ @"\GUIDX", @"(\{0x[A-F0-9]{8},0x[A-F0-9]{4},0x[A-F0-9]{4},\{(0x[A-F0-9]{2},){7}(0x[A-F0-9]{2})\}\})" },
};
@@ -62,11 +68,13 @@ namespace WireMock.RegularExpressions
private static string ReplaceGuidPattern(string pattern)
{
Check.NotNull(pattern, nameof(pattern));
foreach (var tokenPattern in GuidTokenPatterns)
{
pattern = pattern.Replace(tokenPattern.Key, tokenPattern.Value);
}
return pattern;
}
}
}
}

View File

@@ -41,6 +41,7 @@ namespace WireMock.Serialization
var matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch;
bool ignoreCase = matcher.IgnoreCase == true;
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
bool useRegexExtended = _settings.UseRegexExtended == true;
switch (matcherName)
{
@@ -65,7 +66,7 @@ namespace WireMock.Serialization
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0], throwExceptionWhenMatcherFails);
case nameof(RegexMatcher):
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails);
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails, useRegexExtended);
case nameof(JsonMatcher):
object valueForJsonMatcher = matcher.Pattern ?? matcher.Patterns;

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Linq;
using System.Text;
using WireMock.Matchers;
@@ -9,7 +9,7 @@ namespace WireMock.Server
{
public partial class WireMockServer
{
private readonly RegexMatcher _adminFilesFilenamePathMatcher = new RegexMatcher(MatchBehaviour.AcceptOnMatch, @"^\/__admin\/files\/.*$");
private readonly RegexMatcher _adminFilesFilenamePathMatcher = new RegexMatcher(@"^\/__admin\/files\/.*$");
private static readonly Encoding[] FileBodyIsString = { Encoding.UTF8, Encoding.ASCII };
#region Files/{filename}

View File

@@ -1,9 +1,11 @@
using System;
using System.Text.RegularExpressions;
using HandlebarsDotNet;
using JetBrains.Annotations;
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
using WireMock.RegularExpressions;
#if USE_ASPNETCORE
using Microsoft.Extensions.DependencyInjection;
#endif
@@ -215,5 +217,11 @@ namespace WireMock.Settings
/// </summary>
[PublicAPI]
IWebhookSettings WebhookSettings { get; set; }
/// <summary>
/// Use the <see cref="RegexExtended"/> instead of the default <see cref="Regex"/>.
/// </summary>
[PublicAPI]
bool? UseRegexExtended { get; }
}
}

View File

@@ -151,5 +151,9 @@ namespace WireMock.Settings
/// <inheritdoc cref="IWireMockServerSettings.WebhookSettings"/>
[PublicAPI]
public IWebhookSettings WebhookSettings { get; set; }
/// <inheritdoc cref="IWireMockServerSettings.UseRegexExtended"/>
[PublicAPI]
public bool? UseRegexExtended { get; set; } = true;
}
}

View File

@@ -1,3 +1,5 @@
using System;
using FluentAssertions;
using NFluent;
using WireMock.Matchers;
using Xunit;
@@ -70,6 +72,32 @@ namespace WireMock.Net.Tests.Matchers
Check.That(result).IsEqualTo(0.0d);
}
[Fact]
public void RegexMatcher_IsMatch_RegexExtended_Guid()
{
// Assign
var matcher = new RegexMatcher(@"\GUIDB", true);
// Act
double result = matcher.IsMatch(Guid.NewGuid().ToString("B"));
// Assert
result.Should().Be(1.0);
}
[Fact]
public void RegexMatcher_IsMatch_Regex_Guid()
{
// Assign
var matcher = new RegexMatcher(@"\GUIDB", true, false, false);
// Act
double result = matcher.IsMatch(Guid.NewGuid().ToString("B"));
// Assert
result.Should().Be(0);
}
[Fact]
public void RegexMatcher_IsMatch_IgnoreCase()
{

View File

@@ -10,7 +10,7 @@ namespace WireMock.Net.Tests.RegularExpressions
/// <summary>
/// Input guid used for testing
/// </summary>
public Guid InputGuid { get; } = Guid.NewGuid();
public Guid InputGuid => Guid.NewGuid();
[Fact]
public void RegexExtended_GuidB_Pattern()