Skip to content

Commit

Permalink
RegexExtended in settings (#700)
Browse files Browse the repository at this point in the history
* Add extra unittest for RegexExtended

* settings
  • Loading branch information
StefH authored Dec 12, 2021
1 parent 4a434b5 commit 6943b90
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 24 deletions.
26 changes: 12 additions & 14 deletions src/WireMock.Net/Matchers/RegexMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand All @@ -31,7 +31,10 @@ public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
/// </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)
{
}

Expand All @@ -41,16 +44,10 @@ public RegexMatcher([NotNull, RegexPattern] AnyOf<string, StringPattern> pattern
/// <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)
{
}

Expand All @@ -61,7 +58,8 @@ public RegexMatcher([NotNull, RegexPattern] AnyOf<string, StringPattern>[] patte
/// <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));

Expand All @@ -77,7 +75,7 @@ public RegexMatcher(MatchBehaviour matchBehaviour, [NotNull, RegexPattern] AnyOf
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"/>
Expand Down
20 changes: 14 additions & 6 deletions src/WireMock.Net/RegularExpressions/RegexExtended.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ public RegexExtended(string pattern) : this(pattern, RegexOptions.None)
}

/// <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)
{
}
Expand All @@ -35,22 +32,31 @@ public RegexExtended(string pattern,
{
// 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})\}\})" },
};
Expand All @@ -62,11 +68,13 @@ public RegexExtended(string pattern,
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;
}
}
}
}
3 changes: 2 additions & 1 deletion src/WireMock.Net/Serialization/MatcherMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public IMatcher Map([CanBeNull] MatcherModel matcher)
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)
{
Expand All @@ -65,7 +66,7 @@ public IMatcher Map([CanBeNull] MatcherModel matcher)
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;
Expand Down
4 changes: 2 additions & 2 deletions src/WireMock.Net/Server/WireMockServer.AdminFiles.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Linq;
using System.Text;
using WireMock.Matchers;
Expand All @@ -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}
Expand Down
8 changes: 8 additions & 0 deletions src/WireMock.Net/Settings/IWireMockServerSettings.cs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -215,5 +217,11 @@ public interface IWireMockServerSettings
/// </summary>
[PublicAPI]
IWebhookSettings WebhookSettings { get; set; }

/// <summary>
/// Use the <see cref="RegexExtended"/> instead of the default <see cref="Regex"/>.
/// </summary>
[PublicAPI]
bool? UseRegexExtended { get; }
}
}
4 changes: 4 additions & 0 deletions src/WireMock.Net/Settings/WireMockServerSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,9 @@ public class WireMockServerSettings : IWireMockServerSettings
/// <inheritdoc cref="IWireMockServerSettings.WebhookSettings"/>
[PublicAPI]
public IWebhookSettings WebhookSettings { get; set; }

/// <inheritdoc cref="IWireMockServerSettings.UseRegexExtended"/>
[PublicAPI]
public bool? UseRegexExtended { get; set; } = true;
}
}
28 changes: 28 additions & 0 deletions test/WireMock.Net.Tests/Matchers/RegexMatcherTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;
using FluentAssertions;
using NFluent;
using WireMock.Matchers;
using Xunit;
Expand Down Expand Up @@ -70,6 +72,32 @@ public void RegexMatcher_IsMatch_NullInput()
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()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class RegexExtendedTests
/// <summary>
/// Input guid used for testing
/// </summary>
public Guid InputGuid { get; } = Guid.NewGuid();
public Guid InputGuid => Guid.NewGuid();

[Fact]
public void RegexExtended_GuidB_Pattern()
Expand Down

0 comments on commit 6943b90

Please sign in to comment.