diff --git a/examples/WireMock.Net.ConsoleApplication/Program.cs b/examples/WireMock.Net.ConsoleApplication/Program.cs
index b4f808cc..b4c83630 100644
--- a/examples/WireMock.Net.ConsoleApplication/Program.cs
+++ b/examples/WireMock.Net.ConsoleApplication/Program.cs
@@ -71,7 +71,7 @@ namespace WireMock.Net.ConsoleApplication
.WithStatusCode(200));
server
- .Given(Request.Create().WithPath("/partial").UsingPost().WithBody(new SimMetricsMatcher("cat")))
+ .Given(Request.Create().WithPath("/partial").UsingPost().WithBody(new SimMetricsMatcher(new [] { "cat", "dog" })))
.RespondWith(Response.Create().WithStatusCode(200).WithBody("partial = 200"));
// http://localhost:8080/any/any?start=1000&stop=1&stop=2
diff --git a/src/WireMock.Net/Admin/Mappings/MatcherModel.cs b/src/WireMock.Net/Admin/Mappings/MatcherModel.cs
index 3bceaf13..cb71a454 100644
--- a/src/WireMock.Net/Admin/Mappings/MatcherModel.cs
+++ b/src/WireMock.Net/Admin/Mappings/MatcherModel.cs
@@ -21,6 +21,14 @@
///
public string Pattern { get; set; }
+ ///
+ /// Gets or sets the patterns.
+ ///
+ ///
+ /// The patterns.
+ ///
+ public string[] Patterns { get; set; }
+
///
/// Gets or sets the ignore case.
///
diff --git a/src/WireMock.Net/Matchers/ExactMatcher.cs b/src/WireMock.Net/Matchers/ExactMatcher.cs
index 789f6225..fb5354e4 100644
--- a/src/WireMock.Net/Matchers/ExactMatcher.cs
+++ b/src/WireMock.Net/Matchers/ExactMatcher.cs
@@ -1,4 +1,5 @@
-using JetBrains.Annotations;
+using System.Linq;
+using JetBrains.Annotations;
using WireMock.Validation;
namespace WireMock.Matchers
@@ -9,17 +10,17 @@ namespace WireMock.Matchers
///
public class ExactMatcher : IMatcher
{
- private readonly string _value;
+ private readonly string[] _values;
///
/// Initializes a new instance of the class.
///
- /// The value.
- public ExactMatcher([NotNull] string value)
+ /// The values.
+ public ExactMatcher([NotNull] params string[] values)
{
- Check.NotNull(value, nameof(value));
+ Check.NotNull(values, nameof(values));
- _value = value;
+ _values = values;
}
///
@@ -29,16 +30,16 @@ namespace WireMock.Matchers
/// A value between 0.0 - 1.0 of the similarity.
public double IsMatch(string input)
{
- return MatchScores.ToScore(_value.Equals(input));
+ return MatchScores.ToScore(_values.Select(value => value.Equals(input)));
}
///
/// Gets the value.
///
- /// Pattern
- public string GetPattern()
+ /// Patterns
+ public string[] GetPatterns()
{
- return _value;
+ return _values;
}
///
diff --git a/src/WireMock.Net/Matchers/IMatcher.cs b/src/WireMock.Net/Matchers/IMatcher.cs
index 14ea4044..4bcd2cff 100644
--- a/src/WireMock.Net/Matchers/IMatcher.cs
+++ b/src/WireMock.Net/Matchers/IMatcher.cs
@@ -13,10 +13,10 @@
double IsMatch(string input);
///
- /// Gets the pattern.
+ /// Gets the patterns.
///
- /// Pattern
- string GetPattern();
+ /// Patterns
+ string[] GetPatterns();
///
/// Gets the name.
diff --git a/src/WireMock.Net/Matchers/JSONPathMatcher.cs b/src/WireMock.Net/Matchers/JSONPathMatcher.cs
index 09292540..c92b0189 100644
--- a/src/WireMock.Net/Matchers/JSONPathMatcher.cs
+++ b/src/WireMock.Net/Matchers/JSONPathMatcher.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
using WireMock.Validation;
@@ -11,17 +12,17 @@ namespace WireMock.Matchers
///
public class JsonPathMatcher : IMatcher
{
- private readonly string _pattern;
+ private readonly string[] _patterns;
///
/// Initializes a new instance of the class.
///
- /// The pattern.
- public JsonPathMatcher([NotNull] string pattern)
+ /// The patterns.
+ public JsonPathMatcher([NotNull] params string[] patterns)
{
- Check.NotNull(pattern, nameof(pattern));
+ Check.NotNull(patterns, nameof(patterns));
- _pattern = pattern;
+ _patterns = patterns;
}
///
@@ -37,9 +38,8 @@ namespace WireMock.Matchers
try
{
JObject o = JObject.Parse(input);
- JToken token = o.SelectToken(_pattern);
-
- return MatchScores.ToScore(token != null);
+
+ return MatchScores.ToScore(_patterns.Select(p => o.SelectToken(p) != null));
}
catch (Exception)
{
@@ -48,12 +48,12 @@ namespace WireMock.Matchers
}
///
- /// Gets the pattern.
+ /// Gets the patterns.
///
/// Pattern
- public string GetPattern()
+ public string[] GetPatterns()
{
- return _pattern;
+ return _patterns;
}
///
diff --git a/src/WireMock.Net/Matchers/MatchScores.cs b/src/WireMock.Net/Matchers/MatchScores.cs
index 3410ca2b..8aabdfc5 100644
--- a/src/WireMock.Net/Matchers/MatchScores.cs
+++ b/src/WireMock.Net/Matchers/MatchScores.cs
@@ -1,4 +1,8 @@
-namespace WireMock.Matchers
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace WireMock.Matchers
{
///
/// MatchScores
@@ -29,5 +33,27 @@
{
return value ? Perfect : Mismatch;
}
+
+ ///
+ /// Calculates the score from multiple funcs.
+ ///
+ /// The values.
+ /// score
+ public static double ToScore(IEnumerable values)
+ {
+ var list = values.Select(ToScore).ToList();
+ return list.Sum() / list.Count;
+ }
+
+ ///
+ /// Calculates the score from multiple funcs.
+ ///
+ /// The values.
+ /// score
+ public static double ToScore(IEnumerable values)
+ {
+ var list = values.ToList();
+ return list.Sum() / list.Count;
+ }
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/RegexMatcher.cs b/src/WireMock.Net/Matchers/RegexMatcher.cs
index 73b03b6e..918f0e9a 100644
--- a/src/WireMock.Net/Matchers/RegexMatcher.cs
+++ b/src/WireMock.Net/Matchers/RegexMatcher.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
using WireMock.Validation;
@@ -11,25 +12,34 @@ namespace WireMock.Matchers
///
public class RegexMatcher : IMatcher
{
- private readonly string _pattern;
- private readonly Regex _expression;
+ private readonly string[] _patterns;
+ private readonly Regex[] _expressions;
///
/// Initializes a new instance of the class.
///
/// The pattern.
/// IgnoreCase
- public RegexMatcher([NotNull, RegexPattern] string pattern, bool ignoreCase = false)
+ public RegexMatcher([NotNull, RegexPattern] string pattern, bool ignoreCase = false) : this(new [] { pattern }, ignoreCase )
{
- Check.NotNull(pattern, nameof(pattern));
+ }
- _pattern = pattern;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The patterns.
+ /// IgnoreCase
+ public RegexMatcher([NotNull, RegexPattern] string[] patterns, bool ignoreCase = false)
+ {
+ Check.NotNull(patterns, nameof(patterns));
+
+ _patterns = patterns;
RegexOptions options = RegexOptions.Compiled;
if (ignoreCase)
options |= RegexOptions.IgnoreCase;
-
- _expression = new Regex(_pattern, options);
+
+ _expressions = patterns.Select(p => new Regex(p, options)).ToArray();
}
///
@@ -44,7 +54,7 @@ namespace WireMock.Matchers
try
{
- return MatchScores.ToScore(_expression.IsMatch(input));
+ return MatchScores.ToScore(_expressions.Select(e => e.IsMatch(input)));
}
catch (Exception)
{
@@ -53,12 +63,12 @@ namespace WireMock.Matchers
}
///
- /// Gets the pattern.
+ /// Gets the patterns.
///
/// Pattern
- public virtual string GetPattern()
+ public virtual string[] GetPatterns()
{
- return _pattern;
+ return _patterns;
}
///
diff --git a/src/WireMock.Net/Matchers/SimMetricsMatcher.cs b/src/WireMock.Net/Matchers/SimMetricsMatcher.cs
index c4c98ee0..db49d248 100644
--- a/src/WireMock.Net/Matchers/SimMetricsMatcher.cs
+++ b/src/WireMock.Net/Matchers/SimMetricsMatcher.cs
@@ -1,5 +1,7 @@
-using JetBrains.Annotations;
+using System.Linq;
+using JetBrains.Annotations;
using SimMetrics.Net;
+using SimMetrics.Net.API;
using SimMetrics.Net.Metric;
using WireMock.Validation;
@@ -11,7 +13,7 @@ namespace WireMock.Matchers
///
public class SimMetricsMatcher : IMatcher
{
- private readonly string _pattern;
+ private readonly string[] _patterns;
private readonly SimMetricType _simMetricType;
///
@@ -19,11 +21,20 @@ namespace WireMock.Matchers
///
/// The pattern.
/// The SimMetric Type
- public SimMetricsMatcher([NotNull] string pattern, SimMetricType simMetricType = SimMetricType.Levenstein)
+ public SimMetricsMatcher([NotNull] string pattern, SimMetricType simMetricType = SimMetricType.Levenstein) : this(new [] { pattern }, simMetricType)
{
- Check.NotNull(pattern, nameof(pattern));
+ }
- _pattern = pattern;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The patterns.
+ /// The SimMetric Type
+ public SimMetricsMatcher([NotNull] string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein)
+ {
+ Check.NotEmpty(patterns, nameof(patterns));
+
+ _patterns = patterns;
_simMetricType = simMetricType;
}
@@ -33,63 +44,52 @@ namespace WireMock.Matchers
/// The input string
/// A value between 0.0 - 1.0 of the similarity.
public double IsMatch(string input)
+ {
+ IStringMetric m = GetStringMetricType();
+
+ return MatchScores.ToScore(_patterns.Select(p => m.GetSimilarity(p, input)));
+ }
+
+ private IStringMetric GetStringMetricType()
{
switch (_simMetricType)
{
case SimMetricType.BlockDistance:
- var sim2 = new BlockDistance();
- return sim2.GetSimilarity(_pattern, input);
+ return new BlockDistance();
case SimMetricType.ChapmanLengthDeviation:
- var sim3 = new ChapmanLengthDeviation();
- return sim3.GetSimilarity(_pattern, input);
+ return new ChapmanLengthDeviation();
case SimMetricType.CosineSimilarity:
- var sim4 = new CosineSimilarity();
- return sim4.GetSimilarity(_pattern, input);
+ return new CosineSimilarity();
case SimMetricType.DiceSimilarity:
- var sim5 = new DiceSimilarity();
- return sim5.GetSimilarity(_pattern, input);
+ return new DiceSimilarity();
case SimMetricType.EuclideanDistance:
- var sim6 = new EuclideanDistance();
- return sim6.GetSimilarity(_pattern, input);
+ return new EuclideanDistance();
case SimMetricType.JaccardSimilarity:
- var sim7 = new JaccardSimilarity();
- return sim7.GetSimilarity(_pattern, input);
+ return new JaccardSimilarity();
case SimMetricType.Jaro:
- var sim8 = new Jaro();
- return sim8.GetSimilarity(_pattern, input);
+ return new Jaro();
case SimMetricType.JaroWinkler:
- var sim9 = new JaroWinkler();
- return sim9.GetSimilarity(_pattern, input);
+ return new JaroWinkler();
case SimMetricType.MatchingCoefficient:
- var sim10 = new MatchingCoefficient();
- return sim10.GetSimilarity(_pattern, input);
+ return new MatchingCoefficient();
case SimMetricType.MongeElkan:
- var sim11 = new MongeElkan();
- return sim11.GetSimilarity(_pattern, input);
+ return new MongeElkan();
case SimMetricType.NeedlemanWunch:
- var sim12 = new NeedlemanWunch();
- return sim12.GetSimilarity(_pattern, input);
+ return new NeedlemanWunch();
case SimMetricType.OverlapCoefficient:
- var sim13 = new OverlapCoefficient();
- return sim13.GetSimilarity(_pattern, input);
+ return new OverlapCoefficient();
case SimMetricType.QGramsDistance:
- var sim14 = new QGramsDistance();
- return sim14.GetSimilarity(_pattern, input);
+ return new QGramsDistance();
case SimMetricType.SmithWaterman:
- var sim15 = new SmithWaterman();
- return sim15.GetSimilarity(_pattern, input);
+ return new SmithWaterman();
case SimMetricType.SmithWatermanGotoh:
- var sim16 = new SmithWatermanGotoh();
- return sim16.GetSimilarity(_pattern, input);
+ return new SmithWatermanGotoh();
case SimMetricType.SmithWatermanGotohWindowedAffine:
- var sim17 = new SmithWatermanGotohWindowedAffine();
- return sim17.GetSimilarity(_pattern, input);
+ return new SmithWatermanGotohWindowedAffine();
case SimMetricType.ChapmanMeanLength:
- var sim18 = new ChapmanMeanLength();
- return sim18.GetSimilarity(_pattern, input);
+ return new ChapmanMeanLength();
default:
- var sim1 = new Levenstein();
- return sim1.GetSimilarity(_pattern, input);
+ return new Levenstein();
}
}
@@ -97,9 +97,9 @@ namespace WireMock.Matchers
/// Gets the pattern.
///
/// Pattern
- public string GetPattern()
+ public string[] GetPatterns()
{
- return _pattern;
+ return _patterns;
}
///
diff --git a/src/WireMock.Net/Matchers/WildcardMatcher.cs b/src/WireMock.Net/Matchers/WildcardMatcher.cs
index 74690685..1ecbe647 100644
--- a/src/WireMock.Net/Matchers/WildcardMatcher.cs
+++ b/src/WireMock.Net/Matchers/WildcardMatcher.cs
@@ -1,4 +1,5 @@
-using System.Text.RegularExpressions;
+using System.Linq;
+using System.Text.RegularExpressions;
using JetBrains.Annotations;
namespace WireMock.Matchers
@@ -9,25 +10,34 @@ namespace WireMock.Matchers
///
public class WildcardMatcher : RegexMatcher
{
- private readonly string _pattern;
+ private readonly string[] _patterns;
///
/// Initializes a new instance of the class.
///
/// The pattern.
/// IgnoreCase
- public WildcardMatcher([NotNull] string pattern, bool ignoreCase = false) : base("^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$", ignoreCase)
+ public WildcardMatcher([NotNull] string pattern, bool ignoreCase = false) : this(new [] { pattern }, ignoreCase)
{
- _pattern = pattern;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The patterns.
+ /// IgnoreCase
+ public WildcardMatcher([NotNull] string[] patterns, bool ignoreCase = false) : base(patterns.Select(pattern => "^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$").ToArray(), ignoreCase)
+ {
+ _patterns = patterns;
}
///
/// Gets the pattern.
///
/// Pattern
- public override string GetPattern()
+ public override string[] GetPatterns()
{
- return _pattern;
+ return _patterns;
}
///
diff --git a/src/WireMock.Net/Matchers/XPathMatcher.cs b/src/WireMock.Net/Matchers/XPathMatcher.cs
index 1e5af9ed..68011421 100644
--- a/src/WireMock.Net/Matchers/XPathMatcher.cs
+++ b/src/WireMock.Net/Matchers/XPathMatcher.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using System.Xml;
using JetBrains.Annotations;
using WireMock.Validation;
@@ -12,17 +13,17 @@ namespace WireMock.Matchers
///
public class XPathMatcher : IMatcher
{
- private readonly string _pattern;
+ private readonly string[] _patterns;
///
/// Initializes a new instance of the class.
///
- /// The pattern.
- public XPathMatcher([NotNull] string pattern)
+ /// The patterns.
+ public XPathMatcher([NotNull] params string[] patterns)
{
- Check.NotNull(pattern, nameof(pattern));
+ Check.NotNull(patterns, nameof(patterns));
- _pattern = pattern;
+ _patterns = patterns;
}
///
@@ -38,9 +39,8 @@ namespace WireMock.Matchers
try
{
var nav = new XmlDocument { InnerXml = input }.CreateNavigator();
- object result = nav.XPath2Evaluate($"boolean({_pattern})");
- return MatchScores.ToScore(true.Equals(result));
+ return MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.XPath2Evaluate($"boolean({p})"))));
}
catch (Exception)
{
@@ -49,12 +49,12 @@ namespace WireMock.Matchers
}
///
- /// Gets the pattern.
+ /// Gets the patterns.
///
- /// Pattern
- public string GetPattern()
+ /// Patterns
+ public string[] GetPatterns()
{
- return _pattern;
+ return _patterns;
}
///
diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs
index 55c2094f..3d0ecd5a 100644
--- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs
+++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs
@@ -334,40 +334,40 @@ namespace WireMock.Server
Priority = mapping.Priority,
Request = new RequestModel
{
- Path = pathMatchers != null ? new PathModel
+ Path = pathMatchers != null && pathMatchers.Any() ? new PathModel
{
Matchers = Map(pathMatchers.Where(m => m.Matchers != null).SelectMany(m => m.Matchers)),
Funcs = Map(pathMatchers.Where(m => m.Funcs != null).SelectMany(m => m.Funcs))
} : null,
- Url = urlMatchers != null ? new UrlModel
+ Url = urlMatchers != null && urlMatchers.Any() ? new UrlModel
{
Matchers = Map(urlMatchers.Where(m => m.Matchers != null).SelectMany(m => m.Matchers)),
Funcs = Map(urlMatchers.Where(m => m.Funcs != null).SelectMany(m => m.Funcs))
} : null,
- Methods = methodMatcher != null ? methodMatcher.Methods : new[] { "any" },
+ Methods = methodMatcher?.Methods,
- Headers = headerMatchers?.Select(hm => new HeaderModel
+ Headers = headerMatchers != null && headerMatchers.Any() ? headerMatchers?.Select(hm => new HeaderModel
{
Name = hm.Name,
Matchers = Map(hm.Matchers),
Funcs = Map(hm.Funcs)
- }).ToList(),
+ }).ToList() : null,
- Cookies = cookieMatchers?.Select(cm => new CookieModel
+ Cookies = cookieMatchers != null && cookieMatchers.Any() ? cookieMatchers?.Select(cm => new CookieModel
{
Name = cm.Name,
Matchers = Map(cm.Matchers),
Funcs = Map(cm.Funcs)
- }).ToList(),
+ }).ToList() : null,
- Params = paramsMatchers?.Select(pm => new ParamModel
+ Params = paramsMatchers != null && paramsMatchers.Any() ? paramsMatchers?.Select(pm => new ParamModel
{
Name = pm.Key,
Values = pm.Values?.ToList(),
Funcs = Map(pm.Funcs)
- }).ToList(),
+ }).ToList() : null,
Body = new BodyModel
{
@@ -400,10 +400,13 @@ namespace WireMock.Server
if (matcher == null)
return null;
+ var patterns = matcher.GetPatterns();
+
return new MatcherModel
{
Name = matcher.GetName(),
- Pattern = matcher.GetPattern()
+ Pattern = patterns.Length == 1 ? patterns.First() : null,
+ Patterns = patterns.Length > 1 ? patterns : null
};
}
@@ -429,22 +432,24 @@ namespace WireMock.Server
string matcherName = parts[0];
string matcherType = parts.Length > 1 ? parts[1] : null;
+ string[] patterns = matcher.Patterns ?? new[] { matcher.Pattern };
+
switch (matcherName)
{
case "ExactMatcher":
- return new ExactMatcher(matcher.Pattern);
+ return new ExactMatcher(patterns);
case "RegexMatcher":
- return new RegexMatcher(matcher.Pattern);
+ return new RegexMatcher(patterns);
case "JsonPathMatcher":
- return new JsonPathMatcher(matcher.Pattern);
+ return new JsonPathMatcher(patterns);
case "XPathMatcher":
return new XPathMatcher(matcher.Pattern);
case "WildcardMatcher":
- return new WildcardMatcher(matcher.Pattern, matcher.IgnoreCase == true);
+ return new WildcardMatcher(patterns, matcher.IgnoreCase == true);
case "SimMetricsMatcher":
SimMetricType type = SimMetricType.Levenstein;