Add Func<> matchhing. Solves issue #2

This commit is contained in:
Stef Heyenrath
2017-01-18 20:45:38 +01:00
parent 9d1fd8fd51
commit 65c17ff519
16 changed files with 321 additions and 118 deletions

View File

@@ -1,16 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net;
using System.Net.Sockets;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1650:ElementDocumentationMustBeSpelledCorrectly",
Justification = "Reviewed. Suppression is OK here.")]
namespace WireMock.Http
{
/// <summary>
@@ -24,15 +14,21 @@ namespace WireMock.Http
/// <returns>
/// The <see cref="int"/>.
/// </returns>
/// <remarks>see http://stackoverflow.com/questions/138043/find-the-next-tcp-port-in-net. </remarks>
// ReSharper disable once StyleCop.SA1650
/// <remarks>see http://stackoverflow.com/questions/138043/find-the-next-tcp-port-in-net.</remarks>
public static int FindFreeTcpPort()
{
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
TcpListener tcpListener = null;
try
{
tcpListener = new TcpListener(IPAddress.Loopback, 0);
tcpListener.Start();
return ((IPEndPoint)tcpListener.LocalEndpoint).Port;
}
finally
{
tcpListener?.Stop();
}
}
}
}
}

View File

@@ -53,13 +53,6 @@ namespace WireMock.Http
{
_httpHandler = httpHandler;
// .Net Framework is not supportted on XP or Server 2003, so no need for the check
/*if (!HttpListener.IsSupported)
{
Console.WriteLine("Windows XP SP2 or Server 2003 is required to use the HttpListener class.");
return;
}*/
// Create a listener.
_listener = new HttpListener();
_listener.Prefixes.Add(urlPrefix);

View File

@@ -1,3 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
@@ -29,6 +30,11 @@ namespace WireMock
/// </summary>
private readonly Regex bodyRegex;
/// <summary>
/// The body function
/// </summary>
private readonly Func<string, bool> bodyFunc;
/// <summary>
/// Initializes a new instance of the <see cref="RequestBodySpec"/> class.
/// </summary>
@@ -41,6 +47,18 @@ namespace WireMock
bodyRegex = new Regex(body);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestBodySpec"/> class.
/// </summary>
/// <param name="func">
/// The body func.
/// </param>
public RequestBodySpec([NotNull] Func<string, bool> func)
{
Check.NotNull(func, nameof(func));
bodyFunc = func;
}
/// <summary>
/// The is satisfied by.
/// </summary>
@@ -52,7 +70,7 @@ namespace WireMock
/// </returns>
public bool IsSatisfiedBy(RequestMessage requestMessage)
{
return bodyRegex.IsMatch(requestMessage.Body);
return bodyRegex?.IsMatch(requestMessage.Body) ?? bodyFunc(requestMessage.Body);
}
}
}
}

View File

@@ -1,4 +1,6 @@
namespace WireMock.RequestBuilders
using System;
namespace WireMock.RequestBuilders
{
/// <summary>
/// The BodyRequestBuilder interface.
@@ -15,5 +17,16 @@
/// The <see cref="ISpecifyRequests"/>.
/// </returns>
ISpecifyRequests WithBody(string body);
/// <summary>
/// The with body.
/// </summary>
/// <param name="body">
/// The body function.
/// </param>
/// <returns>
/// The <see cref="ISpecifyRequests"/>.
/// </returns>
ISpecifyRequests WithBody(Func<string, bool> body);
}
}

View File

@@ -1,4 +1,8 @@
namespace WireMock.RequestBuilders
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
namespace WireMock.RequestBuilders
{
/// <summary>
/// The HeadersRequestBuilder interface.
@@ -19,5 +23,16 @@
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
IHeadersRequestBuilder WithHeader(string name, string value, bool ignoreCase = true);
/// <summary>
/// The with header.
/// </summary>
/// <param name="func">
/// The headers func.
/// </param>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
IHeadersRequestBuilder WithHeader([NotNull] Func<IDictionary<string, string>, bool> func);
}
}

View File

@@ -1,4 +1,8 @@
namespace WireMock.RequestBuilders
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
namespace WireMock.RequestBuilders
{
/// <summary>
/// The ParametersRequestBuilder interface.
@@ -17,6 +21,17 @@
/// <returns>
/// The <see cref="ISpecifyRequests"/>.
/// </returns>
ISpecifyRequests WithParam(string key, params string[] values);
ISpecifyRequests WithParam([NotNull] string key, params string[] values);
/// <summary>
/// The with parameters.
/// </summary>
/// <param name="func">
/// The func.
/// </param>
/// <returns>
/// The <see cref="ISpecifyRequests"/>.
/// </returns>
ISpecifyRequests WithParam([NotNull] Func<IDictionary<string, List<string>>, bool> func);
}
}

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using JetBrains.Annotations;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
@@ -54,10 +56,25 @@ namespace WireMock.RequestBuilders
/// </returns>
public static IVerbRequestBuilder WithUrl(string url)
{
var specs = new List<ISpecifyRequests>();
var requests = new Request(specs);
specs.Add(new RequestUrlSpec(url));
return requests;
var specs = new List<ISpecifyRequests> { new RequestUrlSpec(url) };
return new Request(specs);
}
/// <summary>
/// The with url.
/// </summary>
/// <param name="func">
/// The url func.
/// </param>
/// <returns>
/// The <see cref="IVerbRequestBuilder"/>.
/// </returns>
public static IVerbRequestBuilder WithUrl(Func<string, bool> func)
{
var specs = new List<ISpecifyRequests> { new RequestUrlSpec(func) };
return new Request(specs);
}
/// <summary>
@@ -71,10 +88,25 @@ namespace WireMock.RequestBuilders
/// </returns>
public static IVerbRequestBuilder WithPath(string path)
{
var specs = new List<ISpecifyRequests>();
var requests = new Request(specs);
specs.Add(new RequestPathSpec(path));
return requests;
var specs = new List<ISpecifyRequests> { new RequestPathSpec(path) };
return new Request(specs);
}
/// <summary>
/// The with path.
/// </summary>
/// <param name="func">
/// The path func.
/// </param>
/// <returns>
/// The <see cref="IVerbRequestBuilder"/>.
/// </returns>
public static IVerbRequestBuilder WithPath([NotNull] Func<string, bool> func)
{
var specs = new List<ISpecifyRequests> { new RequestPathSpec(func) };
return new Request(specs);
}
/// <summary>
@@ -178,6 +210,21 @@ namespace WireMock.RequestBuilders
return this;
}
/// <summary>
/// The with body.
/// </summary>
/// <param name="func">
/// The body function.
/// </param>
/// <returns>
/// The <see cref="ISpecifyRequests"/>.
/// </returns>
public ISpecifyRequests WithBody(Func<string, bool> func)
{
_requestSpecs.Add(new RequestBodySpec(func));
return this;
}
/// <summary>
/// The with parameters.
/// </summary>
@@ -196,6 +243,21 @@ namespace WireMock.RequestBuilders
return this;
}
/// <summary>
/// The with parameters.
/// </summary>
/// <param name="func">
/// The func.
/// </param>
/// <returns>
/// The <see cref="ISpecifyRequests"/>.
/// </returns>
public ISpecifyRequests WithParam(Func<IDictionary<string, List<string>>, bool> func)
{
_requestSpecs.Add(new RequestParamSpec(func));
return this;
}
/// <summary>
/// The with header.
/// </summary>
@@ -214,5 +276,20 @@ namespace WireMock.RequestBuilders
_requestSpecs.Add(new RequestHeaderSpec(name, value, ignoreCase));
return this;
}
/// <summary>
/// The with header.
/// </summary>
/// <param name="func">
/// The func.
/// </param>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
public IHeadersRequestBuilder WithHeader(Func<IDictionary<string, string>, bool> func)
{
_requestSpecs.Add(new RequestHeaderSpec(func));
return this;
}
}
}

View File

@@ -1,6 +1,9 @@
using System.Diagnostics.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
using WireMock.Validation;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
@@ -33,6 +36,11 @@ namespace WireMock
/// </summary>
private readonly Regex patternRegex;
/// <summary>
/// The header function
/// </summary>
private readonly Func<IDictionary<string, string>, bool> headerFunc;
/// <summary>
/// Initializes a new instance of the <see cref="RequestHeaderSpec"/> class.
/// </summary>
@@ -49,6 +57,18 @@ namespace WireMock
patternRegex = ignoreCase ? new Regex(pattern, RegexOptions.IgnoreCase) : new Regex(pattern);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestHeaderSpec"/> class.
/// </summary>
/// <param name="func">
/// The func.
/// </param>
public RequestHeaderSpec([NotNull] Func<IDictionary<string, string>, bool> func)
{
Check.NotNull(func, nameof(func));
headerFunc = func;
}
/// <summary>
/// The is satisfied by.
/// </summary>
@@ -58,8 +78,11 @@ namespace WireMock
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy([NotNull] RequestMessage requestMessage)
public bool IsSatisfiedBy(RequestMessage requestMessage)
{
if (patternRegex == null)
return headerFunc(requestMessage.Headers);
string headerValue = requestMessage.Headers[name];
return patternRegex.IsMatch(headerValue);
}

View File

@@ -18,8 +18,7 @@ using System.Linq;
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1650:ElementDocumentationMustBeSpelledCorrectly",
Justification = "Reviewed. Suppression is OK here.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
@@ -30,7 +29,7 @@ namespace WireMock
/// <summary>
/// The _params.
/// </summary>
private readonly Dictionary<string, List<string>> _params = new Dictionary<string, List<string>>();
private readonly IDictionary<string, List<string>> _params = new Dictionary<string, List<string>>();
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
@@ -50,7 +49,7 @@ namespace WireMock
/// <param name="headers">
/// The headers.
/// </param>
public RequestMessage(string path, string query, string verb, string body, IDictionary<string, string> headers)
public RequestMessage(string path, string query, string verb, string body, IDictionary<string, string> headers = null)
{
if (!string.IsNullOrEmpty(query))
{
@@ -72,12 +71,14 @@ namespace WireMock
dict[key].Add(term.Split('=')[1]);
return dict;
});
Parameters = _params;
}
Path = path;
Headers = headers; //.ToDictionary(kv => kv.Key.ToLower(), kv => kv.Value.ToLower());
Headers = headers;
Verb = verb.ToLower();
Body = body?.Trim() ?? string.Empty;
Body = body;
}
/// <summary>
@@ -111,6 +112,11 @@ namespace WireMock
/// </summary>
public IDictionary<string, string> Headers { get; }
/// <summary>
/// Gets the parameters.
/// </summary>
public IDictionary<string, List<string>> Parameters { get; }
/// <summary>
/// Gets the body.
/// </summary>
@@ -130,4 +136,4 @@ namespace WireMock
return _params.ContainsKey(key) ? _params[key] : new List<string>();
}
}
}
}

View File

@@ -1,7 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using JetBrains.Annotations;
using WireMock.Validation;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
@@ -15,8 +17,7 @@ using JetBrains.Annotations;
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
@@ -32,7 +33,9 @@ namespace WireMock
/// <summary>
/// The _values.
/// </summary>
private readonly List<string> _values;
private readonly IEnumerable<string> _values;
private readonly Func<IDictionary<string, List<string>>, bool> _func;
/// <summary>
/// Initializes a new instance of the <see cref="RequestParamSpec"/> class.
@@ -43,12 +46,27 @@ namespace WireMock
/// <param name="values">
/// The values.
/// </param>
public RequestParamSpec(string key, List<string> values)
public RequestParamSpec([NotNull] string key, [NotNull] IEnumerable<string> values)
{
Check.NotNull(key, nameof(key));
Check.NotNull(values, nameof(values));
_key = key;
_values = values;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestParamSpec"/> class.
/// </summary>
/// <param name="func">
/// The func.
/// </param>
public RequestParamSpec([NotNull] Func<IDictionary<string, List<string>>, bool> func)
{
Check.NotNull(func, nameof(func));
_func = func;
}
/// <summary>
/// The is satisfied by.
/// </summary>
@@ -58,9 +76,14 @@ namespace WireMock
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy([NotNull] RequestMessage requestMessage)
public bool IsSatisfiedBy(RequestMessage requestMessage)
{
return requestMessage.GetParameter(_key).Intersect(_values).Count() == _values.Count;
if (_func != null)
{
return _func(requestMessage.Parameters);
}
return requestMessage.GetParameter(_key).Intersect(_values).Count() == _values.Count();
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
using WireMock.Validation;
@@ -15,8 +16,7 @@ using WireMock.Validation;
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
@@ -25,9 +25,14 @@ namespace WireMock
public class RequestPathSpec : ISpecifyRequests
{
/// <summary>
/// The _path.
/// The pathRegex.
/// </summary>
private readonly Regex _path;
private readonly Regex pathRegex;
/// <summary>
/// The url function
/// </summary>
private readonly Func<string, bool> pathFunc;
/// <summary>
/// Initializes a new instance of the <see cref="RequestPathSpec"/> class.
@@ -38,7 +43,19 @@ namespace WireMock
public RequestPathSpec([NotNull, RegexPattern] string path)
{
Check.NotNull(path, nameof(path));
_path = new Regex(path);
pathRegex = new Regex(path);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestPathSpec"/> class.
/// </summary>
/// <param name="func">
/// The url func.
/// </param>
public RequestPathSpec([NotNull] Func<string, bool> func)
{
Check.NotNull(func, nameof(func));
pathFunc = func;
}
/// <summary>
@@ -50,9 +67,9 @@ namespace WireMock
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy([NotNull] RequestMessage requestMessage)
public bool IsSatisfiedBy(RequestMessage requestMessage)
{
return _path.IsMatch(requestMessage.Path);
return pathRegex?.IsMatch(requestMessage.Path) ?? pathFunc(requestMessage.Path);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System;
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using System.Text.RegularExpressions;
using WireMock.Validation;
@@ -29,6 +30,11 @@ namespace WireMock
/// </summary>
private readonly Regex urlRegex;
/// <summary>
/// The url function
/// </summary>
private readonly Func<string, bool> urlFunc;
/// <summary>
/// Initializes a new instance of the <see cref="RequestUrlSpec"/> class.
/// </summary>
@@ -41,6 +47,18 @@ namespace WireMock
urlRegex = new Regex(url);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestUrlSpec"/> class.
/// </summary>
/// <param name="func">
/// The url func.
/// </param>
public RequestUrlSpec(Func<string, bool> func)
{
Check.NotNull(func, nameof(func));
urlFunc = func;
}
/// <summary>
/// The is satisfied by.
/// </summary>
@@ -52,7 +70,7 @@ namespace WireMock
/// </returns>
public bool IsSatisfiedBy(RequestMessage requestMessage)
{
return urlRegex.IsMatch(requestMessage.Url);
return urlRegex?.IsMatch(requestMessage.Url) ?? urlFunc(requestMessage.Url);
}
}
}
}

View File

@@ -28,16 +28,6 @@ namespace WireMock
/// </summary>
private readonly IDictionary<string, string> _headers = new ConcurrentDictionary<string, string>();
/// <summary>
/// The status code.
/// </summary>
private volatile int statusCode = 200;
/// <summary>
/// The body.
/// </summary>
private volatile string body;
/// <summary>
/// Gets the headers.
/// </summary>
@@ -46,34 +36,12 @@ namespace WireMock
/// <summary>
/// Gets or sets the status code.
/// </summary>
public int StatusCode
{
get
{
return statusCode;
}
set
{
statusCode = value;
}
}
public int StatusCode { get; set; } = 200;
/// <summary>
/// Gets or sets the body.
/// </summary>
public string Body
{
get
{
return body;
}
set
{
body = value;
}
}
public string Body { get; set; }
/// <summary>
/// The add header.