GUID Pattern support in RegexMatcher (#699)

* Add the RegexGuid class

* Use of RegexGuid in the RegexMatcher

* Fix up the CodeFactor violations

* Rename RegexGuid --> RegexExtended
This commit is contained in:
Michael Brogdon
2021-12-11 02:57:15 -07:00
committed by GitHub
parent 3dafd2e725
commit 4a434b5dba
3 changed files with 175 additions and 2 deletions

View File

@@ -5,6 +5,7 @@ using AnyOfTypes;
using JetBrains.Annotations;
using WireMock.Extensions;
using WireMock.Models;
using WireMock.RegularExpressions;
using WireMock.Validation;
namespace WireMock.Matchers
@@ -17,7 +18,7 @@ namespace WireMock.Matchers
public class RegexMatcher : IStringMatcher, IIgnoreCaseMatcher
{
private readonly AnyOf<string, StringPattern>[] _patterns;
private readonly Regex[] _expressions;
private readonly RegexExtended[] _expressions;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
@@ -76,7 +77,7 @@ namespace WireMock.Matchers
options |= RegexOptions.IgnoreCase;
}
_expressions = patterns.Select(p => new Regex(p.GetPattern(), options)).ToArray();
_expressions = patterns.Select(p => new RegexExtended(p.GetPattern(), options)).ToArray();
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using WireMock.Validation;
namespace WireMock.RegularExpressions
{
/// <summary>
/// Extension to the <see cref="Regex"/> object, adding support for GUID tokens for matching on.
/// </summary>
public class RegexExtended : Regex
{
/// <inheritdoc cref="Regex"/>
public RegexExtended(string pattern) : this(pattern, RegexOptions.None)
{
}
/// <inheritdoc cref="Regex"/>
public RegexExtended(string pattern,
RegexOptions options)
: this(pattern, options, Regex.InfiniteMatchTimeout)
{
}
/// <inheritdoc cref="Regex"/>
public RegexExtended(string pattern,
RegexOptions options,
TimeSpan matchTimeout)
: base(ReplaceGuidPattern(pattern), options, matchTimeout)
{
}
// Dictionary of various Guid tokens with a corresponding regular expression pattern to use instead.
private static readonly Dictionary<string, string> GuidTokenPatterns = new Dictionary<string, string>
{
// 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})\}\})" },
};
/// <summary>
/// Replaces all instances of valid GUID tokens with the correct regular expression to match.
/// </summary>
/// <param name="pattern">Pattern to replace token for.</param>
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

@@ -0,0 +1,100 @@
using System;
using NFluent;
using WireMock.RegularExpressions;
using Xunit;
namespace WireMock.Net.Tests.RegularExpressions
{
public class RegexExtendedTests
{
/// <summary>
/// Input guid used for testing
/// </summary>
public Guid InputGuid { get; } = Guid.NewGuid();
[Fact]
public void RegexExtended_GuidB_Pattern()
{
var guidbUpper = @".*\GUIDB.*";
var guidbLower = @".*\guidb.*";
var inputLower = InputGuid.ToString("B");
var inputUpper = InputGuid.ToString("B").ToUpper();
var regexLower = new RegexExtended(guidbLower);
var regexUpper = new RegexExtended(guidbUpper);
Check.That(regexLower.IsMatch(inputLower)).Equals(true);
Check.That(regexLower.IsMatch(inputUpper)).Equals(false);
Check.That(regexUpper.IsMatch(inputUpper)).Equals(true);
Check.That(regexUpper.IsMatch(inputLower)).Equals(false);
}
[Fact]
public void RegexExtended_GuidD_Pattern()
{
var guiddUpper = @".*\GUIDD.*";
var guiddLower = @".*\guidd.*";
var inputLower = InputGuid.ToString("D");
var inputUpper = InputGuid.ToString("D").ToUpper();
var regexLower = new RegexExtended(guiddLower);
var regexUpper = new RegexExtended(guiddUpper);
Check.That(regexLower.IsMatch(inputLower)).Equals(true);
Check.That(regexLower.IsMatch(inputUpper)).Equals(false);
Check.That(regexUpper.IsMatch(inputUpper)).Equals(true);
Check.That(regexUpper.IsMatch(inputLower)).Equals(false);
}
[Fact]
public void RegexExtended_GuidN_Pattern()
{
var guidnUpper = @".*\GUIDN.*";
var guidnLower = @".*\guidn.*";
var inputLower = InputGuid.ToString("N");
var inputUpper = InputGuid.ToString("N").ToUpper();
var regexLower = new RegexExtended(guidnLower);
var regexUpper = new RegexExtended(guidnUpper);
Check.That(regexLower.IsMatch(inputLower)).Equals(true);
Check.That(regexLower.IsMatch(inputUpper)).Equals(false);
Check.That(regexUpper.IsMatch(inputUpper)).Equals(true);
Check.That(regexUpper.IsMatch(inputLower)).Equals(false);
}
[Fact]
public void RegexExtended_GuidP_Pattern()
{
var guidpUpper = @".*\GUIDP.*";
var guidpLower = @".*\guidp.*";
var inputLower = InputGuid.ToString("P");
var inputUpper = InputGuid.ToString("P").ToUpper();
var regexLower = new RegexExtended(guidpLower);
var regexUpper = new RegexExtended(guidpUpper);
Check.That(regexLower.IsMatch(inputLower)).Equals(true);
Check.That(regexLower.IsMatch(inputUpper)).Equals(false);
Check.That(regexUpper.IsMatch(inputUpper)).Equals(true);
Check.That(regexUpper.IsMatch(inputLower)).Equals(false);
}
[Fact]
public void RegexExtended_GuidX_Pattern()
{
var guidxUpper = @".*\GUIDX.*";
var guidxLower = @".*\guidx.*";
var inputLower = InputGuid.ToString("X");
var inputUpper = InputGuid.ToString("X").ToUpper().Replace("X", "x");
var regexLower = new RegexExtended(guidxLower);
var regexUpper = new RegexExtended(guidxUpper);
Check.That(regexLower.IsMatch(inputLower)).Equals(true);
Check.That(regexLower.IsMatch(inputUpper)).Equals(false);
Check.That(regexUpper.IsMatch(inputUpper)).Equals(true);
Check.That(regexUpper.IsMatch(inputLower)).Equals(false);
}
}
}