diff --git a/src/MockHttp/Matchers/Patterns/RegexPatternMatcher.cs b/src/MockHttp/Matchers/Patterns/RegexPatternMatcher.cs
index 1b179c01..2ce2116e 100644
--- a/src/MockHttp/Matchers/Patterns/RegexPatternMatcher.cs
+++ b/src/MockHttp/Matchers/Patterns/RegexPatternMatcher.cs
@@ -5,8 +5,6 @@ namespace MockHttp.Matchers.Patterns;
internal class RegexPatternMatcher : PatternMatcher
{
- private readonly Regex _regex;
-
public RegexPatternMatcher
(
#if NET7_0_OR_GREATER
@@ -20,18 +18,20 @@ string regex
public RegexPatternMatcher(Regex regex)
{
- _regex = regex ?? throw new ArgumentNullException(nameof(regex));
+ Regex = regex ?? throw new ArgumentNullException(nameof(regex));
}
+ internal Regex Regex { get; }
+
///
public override bool IsMatch(string value)
{
- return _regex.IsMatch(value);
+ return Regex.IsMatch(value);
}
///
public override string ToString()
{
- return _regex.ToString();
+ return Regex.ToString();
}
}
diff --git a/src/MockHttp/Matchers/Patterns/WildcardPatternMatcher.cs b/src/MockHttp/Matchers/Patterns/WildcardPatternMatcher.cs
index 941e5425..8ce1e300 100644
--- a/src/MockHttp/Matchers/Patterns/WildcardPatternMatcher.cs
+++ b/src/MockHttp/Matchers/Patterns/WildcardPatternMatcher.cs
@@ -4,6 +4,8 @@ namespace MockHttp.Matchers.Patterns;
internal sealed class WildcardPatternMatcher : RegexPatternMatcher
{
+ private static readonly char[] SpecialRegexChars = ['.', '+', '*', '?', '^', '$', '(', ')', '[', ']', '{', '}', '|', '\\'];
+
private readonly string _pattern;
public WildcardPatternMatcher(string pattern)
@@ -47,7 +49,7 @@ private static string GetMatchPattern(string pattern)
IEnumerable matchGroups = pattern
.Split('*')
.Where(s => !string.IsNullOrEmpty(s))
- .Select(s => $"({s})");
+ .Select(s => $"({RegexUriEscape(s)})");
sb.Append(string.Join(".+", matchGroups));
@@ -55,4 +57,20 @@ private static string GetMatchPattern(string pattern)
return sb.ToString();
}
+
+ private static string RegexUriEscape(string s)
+ {
+ var sb = new StringBuilder();
+ foreach (char ch in s)
+ {
+ if (SpecialRegexChars.Contains(ch))
+ {
+ sb.Append('\\');
+ }
+
+ sb.Append(ch);
+ }
+
+ return sb.ToString();
+ }
}
diff --git a/test/MockHttp.Tests/Matchers/Patterns/WildcardPatternMatcherTests.cs b/test/MockHttp.Tests/Matchers/Patterns/WildcardPatternMatcherTests.cs
new file mode 100644
index 00000000..5e1b9754
--- /dev/null
+++ b/test/MockHttp.Tests/Matchers/Patterns/WildcardPatternMatcherTests.cs
@@ -0,0 +1,46 @@
+namespace MockHttp.Matchers.Patterns;
+
+public sealed class WildcardPatternMatcherTests
+{
+ [Theory]
+ [InlineData("test", "^(test)$")]
+ [InlineData("test*", "^(test).*")]
+ [InlineData("*test", ".*(test)$")]
+ [InlineData("*test*", ".*(test).*")]
+ [InlineData("*test1*test2*", ".*(test1).+(test2).*")]
+ [InlineData("/path?*", "^(/path\\?).*")]
+ [InlineData("/path/file.jpg?q=*&p=1&m=[a,b]", "^(/path/file\\.jpg\\?q=).+(&p=1&m=\\[a,b\\])$")]
+ [InlineData(".+?^$()[]{}|\\", "^(\\.\\+\\?\\^\\$\\(\\)\\[\\]\\{\\}\\|\\\\)$")]
+ public void When_creating_matcher_it_should_generate_expected_regex(string wildcardPattern, string expectedRegex)
+ {
+ var sut = new WildcardPatternMatcher(wildcardPattern);
+ sut.Regex.ToString().Should().Be(expectedRegex);
+ }
+
+ [Theory]
+ [InlineData("test", "test", true)]
+ [InlineData("test", "testing", false)]
+ [InlineData("test*", "test", true)]
+ [InlineData("test*", "testing", true)]
+ [InlineData("test*", "stress testing", false)]
+ [InlineData("*test", "test", true)]
+ [InlineData("*test", "testing", false)]
+ [InlineData("*test", "stress test", true)]
+ [InlineData("*test*", "test", true)]
+ [InlineData("*test*", "testing", true)]
+ [InlineData("*test*", "stress testing", true)]
+ [InlineData("*test*", "tes", false)]
+ [InlineData("*test1*test2*", "test1 test2", true)]
+ [InlineData("*test1*test2*", "test0 test1 test2 test3", true)]
+ [InlineData("*test1*test2*", "test test2", false)]
+ [InlineData("/path?q=*", "/path?q=1", true)]
+ [InlineData("/path?q=*", "/path?v=1&q=1", false)]
+ [InlineData("/path/file.jpg?q=*&p=1&m=[a,b]", "/path/file.jpg?q=search%20term&p=1&m=[a,b]", true)]
+ [InlineData("/path/file.jpg?q=*&p=1&m=[a,b]", "/path/file.jpg?q=search%20term&p=1&m=(a,b)", false)]
+ [InlineData("/path/file.jpg?q=*&p=*&m=*", "/path/file.jpg?q=search%20term&p=1&m=[a,b]", true)]
+ public void Given_that_value_matches_pattern_when_matching_it_should_pass(string wildcardPattern, string value, bool expected)
+ {
+ var sut = new WildcardPatternMatcher(wildcardPattern);
+ sut.IsMatch(value).Should().Be(expected);
+ }
+}