GET "/__admin/mappings"

This commit is contained in:
Stef Heyenrath
2017-01-24 22:06:25 +01:00
parent 45aa83ee91
commit 3f84ba8b20
44 changed files with 805 additions and 302 deletions
@@ -5,7 +5,6 @@ using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Server; using WireMock.Server;
namespace WireMock.Net.ConsoleApplication namespace WireMock.Net.ConsoleApplication
{ {
static class Program static class Program
@@ -14,9 +13,9 @@ namespace WireMock.Net.ConsoleApplication
{ {
int port; int port;
if (args.Length == 0 || !int.TryParse(args[0], out port)) if (args.Length == 0 || !int.TryParse(args[0], out port))
port = 8080; port = 9090;
var server = FluentMockServer.Start(port); var server = FluentMockServer.StartWithAdminInterface(port);
Console.WriteLine("FluentMockServer running at {0}", server.Port); Console.WriteLine("FluentMockServer running at {0}", server.Port);
server server
@@ -24,17 +23,17 @@ namespace WireMock.Net.ConsoleApplication
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithStatusCode(200) .WithStatusCode(200)
.WithHeader("Content-Type", "application/json") .WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""/x with FUNC 200""}")); .WithBody(@"{ ""result"": ""Contains x with FUNC 200""}"));
// http://localhost:8080/gffgfgf/sddsds?start=1000&stop=1&stop=2 // http://localhost:8080/gffgfgf/sddsds?start=1000&stop=1&stop=2
server server
.Given(Request.Create().WithUrl("/*").UsingGet()) .Given(Request.Create().WithUrl("/*").UsingGet().WithParam("start"))
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithStatusCode(200) .WithStatusCode(200)
.WithHeader("Content-Type", "application/json") .WithHeader("Content-Type", "application/json")
.WithHeader("Transformed-Postman-Token", "token is {{request.headers.Postman-Token}}") .WithHeader("Transformed-Postman-Token", "token is {{request.headers.Postman-Token}}")
.WithBody(@"{""msg"": ""Hello world! : {{request.url}} : {{request.path}} : .WithBody(@"{""msg"": ""Hello world, {{request.url}}, {{request.path}} :
bykey={{request.query.start}} : bykey={{request.query.stop}} byidx0={{request.query.stop.[0]}} byidx1={{request.query.stop.[1]}}""") bykey={{request.query.start}}, bykey={{request.query.stop}}, byidx0={{request.query.stop.[0]}}, byidx1={{request.query.stop.[1]}}""")
.WithTransformer() .WithTransformer()
.WithDelay(TimeSpan.FromMilliseconds(100)) .WithDelay(TimeSpan.FromMilliseconds(100))
); );
@@ -47,7 +46,7 @@ namespace WireMock.Net.ConsoleApplication
.WithBody(@"{ ""result"": ""data posted with FUNC 201""}")); .WithBody(@"{ ""result"": ""data posted with FUNC 201""}"));
server server
.Given(Request.Create().WithUrl("/data", "/ax").UsingPost()) .Given(Request.Create().WithUrl("/data", "/ax").UsingPost().WithHeader("Content-Type", "application/json*"))
.RespondWith(Response.Create() .RespondWith(Response.Create()
.WithStatusCode(201) .WithStatusCode(201)
.WithHeader("Content-Type", "application/json") .WithHeader("Content-Type", "application/json")
@@ -60,6 +59,13 @@ namespace WireMock.Net.ConsoleApplication
.WithHeader("Content-Type", "application/json") .WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""json posted with 201""}")); .WithBody(@"{ ""result"": ""json posted with 201""}"));
server
.Given(Request.Create().WithUrl("/json2").UsingPost().WithBody("x"))
.RespondWith(Response.Create()
.WithStatusCode(201)
.WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""json posted with x - 201""}"));
server server
.Given(Request.Create().WithUrl("/data").UsingDelete()) .Given(Request.Create().WithUrl("/data").UsingDelete())
.RespondWith(Response.Create() .RespondWith(Response.Create()
@@ -67,6 +73,11 @@ namespace WireMock.Net.ConsoleApplication
.WithHeader("Content-Type", "application/json") .WithHeader("Content-Type", "application/json")
.WithBody(@"{ ""result"": ""data deleted with 200""}")); .WithBody(@"{ ""result"": ""data deleted with 200""}"));
server
.Given(Request.Create().WithUrl("/nobody").UsingGet())
.RespondWith(Response.Create()
.WithStatusCode(200));
Console.WriteLine("Press any key to stop the server"); Console.WriteLine("Press any key to stop the server");
Console.ReadKey(); Console.ReadKey();
+16
View File
@@ -0,0 +1,16 @@
namespace WireMock.Admin
{
/// <summary>
/// Body Model
/// </summary>
public class BodyModel
{
/// <summary>
/// Gets or sets the matcher.
/// </summary>
/// <value>
/// The matcher.
/// </value>
public MatcherModel Matcher { get; set; }
}
}
+26
View File
@@ -0,0 +1,26 @@
using System.Collections.Generic;
namespace WireMock.Admin
{
/// <summary>
/// Cookie Model
/// </summary>
public class CookieModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the matchers.
/// </summary>
/// <value>
/// The matchers.
/// </value>
public IList<MatcherModel> Matchers { get; set; }
}
}
+7
View File
@@ -0,0 +1,7 @@
//namespace WireMock.Admin
//{
// public class FuncModel
// {
// public string Name { get; set; }
// }
//}
+26
View File
@@ -0,0 +1,26 @@
using System.Collections.Generic;
namespace WireMock.Admin
{
/// <summary>
/// Header Model
/// </summary>
public class HeaderModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the matchers.
/// </summary>
/// <value>
/// The matchers.
/// </value>
public IList<MatcherModel> Matchers { get; set; }
}
}
+34
View File
@@ -0,0 +1,34 @@
using System;
namespace WireMock.Admin
{
/// <summary>
/// MappingModel
/// </summary>
public class MappingModel
{
/// <summary>
/// Gets or sets the unique identifier.
/// </summary>
/// <value>
/// The unique identifier.
/// </value>
public Guid Guid { get; set; }
/// <summary>
/// Gets or sets the request.
/// </summary>
/// <value>
/// The request.
/// </value>
public RequestModel Request { get; set; }
/// <summary>
/// Gets or sets the response.
/// </summary>
/// <value>
/// The response.
/// </value>
public ResponseModel Response { get; set; }
}
}
+24
View File
@@ -0,0 +1,24 @@
namespace WireMock.Admin
{
/// <summary>
/// MatcherModel
/// </summary>
public class MatcherModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the pattern.
/// </summary>
/// <value>
/// The pattern.
/// </value>
public string Pattern { get; set; }
}
}
+26
View File
@@ -0,0 +1,26 @@
using System.Collections.Generic;
namespace WireMock.Admin
{
/// <summary>
/// Param Model
/// </summary>
public class ParamModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the values.
/// </summary>
/// <value>
/// The values.
/// </value>
public IList<string> Values { get; set; }
}
}
+55
View File
@@ -0,0 +1,55 @@
using System.Collections.Generic;
namespace WireMock.Admin
{
/// <summary>
/// RequestModel
/// </summary>
public class RequestModel
{
/// <summary>
/// Gets or sets the URL.
/// </summary>
/// <value>
/// The URL.
/// </value>
public UrlModel Url { get; set; }
/// <summary>
/// The verbs
/// </summary>
public string[] Verbs { get; set; }
/// <summary>
/// Gets or sets the Headers.
/// </summary>
/// <value>
/// The Headers.
/// </value>
public IList<HeaderModel> Headers { get; set; }
/// <summary>
/// Gets or sets the Cookies.
/// </summary>
/// <value>
/// The Cookies.
/// </value>
public IList<CookieModel> Cookies { get; set; }
/// <summary>
/// Gets or sets the Params.
/// </summary>
/// <value>
/// The Headers.
/// </value>
public IList<ParamModel> Params { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
/// <value>
/// The body.
/// </value>
public BodyModel Body { get; set; }
}
}
+34
View File
@@ -0,0 +1,34 @@
using System.Collections.Generic;
namespace WireMock.Admin
{
/// <summary>
/// ResponseModel
/// </summary>
public class ResponseModel
{
/// <summary>
/// Gets or sets the HTTP status.
/// </summary>
/// <value>
/// The HTTP status.
/// </value>
public int StatusCode { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
/// <value>
/// The body.
/// </value>
public string Body { get; set; }
/// <summary>
/// Gets or sets the headers.
/// </summary>
/// <value>
/// The headers.
/// </value>
public IDictionary<string, string> Headers { get; set; }
}
}
+18
View File
@@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace WireMock.Admin
{
/// <summary>
/// UrlModel
/// </summary>
public class UrlModel
{
/// <summary>
/// Gets or sets the matchers.
/// </summary>
/// <value>
/// The matchers.
/// </value>
public IList<MatcherModel> Matchers { get; set; }
}
}
+24
View File
@@ -0,0 +1,24 @@
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Validation;
namespace WireMock
{
internal class DynamicResponseProvider : IResponseProvider
{
private readonly Func<ResponseMessage> _responseMessageFunc;
public DynamicResponseProvider([NotNull] Func<ResponseMessage> responseMessageFunc)
{
Check.NotNull(responseMessageFunc, nameof(responseMessageFunc));
_responseMessageFunc = responseMessageFunc;
}
public Task<ResponseMessage> ProvideResponse(RequestMessage requestMessage)
{
return Task.FromResult(_responseMessageFunc());
}
}
}
@@ -1,17 +1,11 @@
using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks;
using System.Threading.Tasks;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
namespace WireMock namespace WireMock
{ {
/// <summary> /// <summary>
/// The ProvideResponses interface. /// The Response Provider interface.
/// </summary> /// </summary>
public interface IProvideResponses public interface IResponseProvider
{ {
/// <summary> /// <summary>
/// The provide response. /// The provide response.
@@ -6,24 +6,24 @@ namespace WireMock
/// <summary> /// <summary>
/// The route. /// The route.
/// </summary> /// </summary>
public class Route public class Mapping
{ {
/// <summary> /// <summary>
/// The _request matcher. /// The Request matcher.
/// </summary> /// </summary>
public IRequestMatcher RequestMatcher { get; } public IRequestMatcher RequestMatcher { get; }
/// <summary> /// <summary>
/// The _provider. /// The Provider.
/// </summary> /// </summary>
public IProvideResponses Provider { get; } public IResponseProvider Provider { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Route"/> class. /// Initializes a new instance of the <see cref="Mapping"/> class.
/// </summary> /// </summary>
/// <param name="requestMatcher">The request matcher.</param> /// <param name="requestMatcher">The request matcher.</param>
/// <param name="provider">The provider.</param> /// <param name="provider">The provider.</param>
public Route(IRequestMatcher requestMatcher, IProvideResponses provider) public Mapping(IRequestMatcher requestMatcher, IResponseProvider provider)
{ {
RequestMatcher = requestMatcher; RequestMatcher = requestMatcher;
Provider = provider; Provider = provider;
+6
View File
@@ -13,5 +13,11 @@
/// <c>true</c> if the specified input is match; otherwise, <c>false</c>. /// <c>true</c> if the specified input is match; otherwise, <c>false</c>.
/// </returns> /// </returns>
bool IsMatch(string input); bool IsMatch(string input);
/// <summary>
/// Gets the pattern.
/// </summary>
/// <returns>Pattern</returns>
string GetPattern();
} }
} }
+9
View File
@@ -48,5 +48,14 @@ namespace WireMock.Matchers
return false; return false;
} }
} }
/// <summary>
/// Gets the pattern.
/// </summary>
/// <returns>Pattern</returns>
public string GetPattern()
{
return _pattern;
}
} }
} }
+12 -1
View File
@@ -11,6 +11,7 @@ namespace WireMock.Matchers
/// <seealso cref="WireMock.Matchers.IMatcher" /> /// <seealso cref="WireMock.Matchers.IMatcher" />
public class RegexMatcher : IMatcher public class RegexMatcher : IMatcher
{ {
private readonly string _pattern;
private readonly Regex _expression; private readonly Regex _expression;
/// <summary> /// <summary>
@@ -21,7 +22,8 @@ namespace WireMock.Matchers
{ {
Check.NotNull(pattern, nameof(pattern)); Check.NotNull(pattern, nameof(pattern));
_expression = new Regex(pattern, RegexOptions.Compiled); _pattern = pattern;
_expression = new Regex(_pattern, RegexOptions.Compiled);
} }
/// <summary> /// <summary>
@@ -45,5 +47,14 @@ namespace WireMock.Matchers
return false; return false;
} }
} }
/// <summary>
/// Gets the pattern.
/// </summary>
/// <returns>Pattern</returns>
public string GetPattern()
{
return _pattern;
}
} }
} }
@@ -19,11 +19,6 @@ namespace WireMock.Matchers.Request
/// </summary> /// </summary>
private readonly byte[] _bodyData; private readonly byte[] _bodyData;
/// <summary>
/// The matcher.
/// </summary>
private readonly IMatcher _matcher;
/// <summary> /// <summary>
/// The body function /// The body function
/// </summary> /// </summary>
@@ -34,6 +29,11 @@ namespace WireMock.Matchers.Request
/// </summary> /// </summary>
private readonly Func<byte[], bool> _bodyDataFunc; private readonly Func<byte[], bool> _bodyDataFunc;
/// <summary>
/// The matcher.
/// </summary>
public readonly IMatcher Matcher;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary> /// </summary>
@@ -91,7 +91,7 @@ namespace WireMock.Matchers.Request
public RequestMessageBodyMatcher([NotNull] IMatcher matcher) public RequestMessageBodyMatcher([NotNull] IMatcher matcher)
{ {
Check.NotNull(matcher, nameof(matcher)); Check.NotNull(matcher, nameof(matcher));
_matcher = matcher; Matcher = matcher;
} }
/// <summary> /// <summary>
@@ -103,8 +103,8 @@ namespace WireMock.Matchers.Request
/// </returns> /// </returns>
public bool IsMatch(RequestMessage requestMessage) public bool IsMatch(RequestMessage requestMessage)
{ {
if (_matcher != null) if (Matcher != null)
return _matcher.IsMatch(requestMessage.Body); return Matcher.IsMatch(requestMessage.Body);
if (_body != null) if (_body != null)
return requestMessage.Body == _body; return requestMessage.Body == _body;
@@ -1,13 +1,14 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Validation;
namespace WireMock.Matchers.Request namespace WireMock.Matchers.Request
{ {
/// <summary> /// <summary>
/// The composite request matcher. /// The composite request matcher.
/// </summary> /// </summary>
public class RequestMessageCompositeMatcher : IRequestMatcher public abstract class RequestMessageCompositeMatcher : IRequestMatcher
{ {
private readonly CompositeMatcherType _type; private readonly CompositeMatcherType _type;
@@ -17,15 +18,17 @@ namespace WireMock.Matchers.Request
/// <value> /// <value>
/// The request matchers. /// The request matchers.
/// </value> /// </value>
public IEnumerable<IRequestMatcher> RequestMatchers { get; } private IEnumerable<IRequestMatcher> RequestMatchers { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCompositeMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageCompositeMatcher"/> class.
/// </summary> /// </summary>
/// <param name="requestMatchers">The request matchers.</param> /// <param name="requestMatchers">The request matchers.</param>
/// <param name="type">The CompositeMatcherType type (Defaults to 'And')</param> /// <param name="type">The CompositeMatcherType type (Defaults to 'And')</param>
public RequestMessageCompositeMatcher([NotNull] IEnumerable<IRequestMatcher> requestMatchers, CompositeMatcherType type = CompositeMatcherType.And) protected RequestMessageCompositeMatcher([NotNull] IEnumerable<IRequestMatcher> requestMatchers, CompositeMatcherType type = CompositeMatcherType.And)
{ {
Check.NotNull(requestMatchers, nameof(requestMatchers));
_type = type; _type = type;
RequestMatchers = requestMatchers; RequestMatchers = requestMatchers;
} }
@@ -37,11 +40,11 @@ namespace WireMock.Matchers.Request
/// <returns> /// <returns>
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>. /// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
/// </returns> /// </returns>
public bool IsMatch(RequestMessage requestMessage) public virtual bool IsMatch(RequestMessage requestMessage)
{ {
return _type == CompositeMatcherType.And ? return _type == CompositeMatcherType.And ?
RequestMatchers.All(spec => spec.IsMatch(requestMessage)) : RequestMatchers.All(matcher => matcher.IsMatch(requestMessage)) :
RequestMatchers.Any(spec => spec.IsMatch(requestMessage)); RequestMatchers.Any(matcher => matcher.IsMatch(requestMessage));
} }
} }
} }
@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Validation; using WireMock.Validation;
@@ -10,12 +11,21 @@ namespace WireMock.Matchers.Request
/// </summary> /// </summary>
public class RequestMessageCookieMatcher : IRequestMatcher public class RequestMessageCookieMatcher : IRequestMatcher
{ {
private readonly string _name; private readonly Func<IDictionary<string, string>, bool>[] _cookieFuncs;
private readonly IMatcher _matcher; /// <summary>
/// The name
private readonly Func<IDictionary<string, string>, bool> _cookieFunc; /// </summary>
public string Name { get; }
/// <summary>
/// Gets the matchers.
/// </summary>
/// <value>
/// The matchers.
/// </value>
public IMatcher[] Matchers { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary> /// </summary>
@@ -27,20 +37,18 @@ namespace WireMock.Matchers.Request
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
Check.NotNull(pattern, nameof(pattern)); Check.NotNull(pattern, nameof(pattern));
_name = name; Name = name;
_matcher = new WildcardMatcher(pattern, ignoreCase); Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
/// </summary> /// </summary>
/// <param name="func"> /// <param name="funcs">The funcs.</param>
/// The func. public RequestMessageCookieMatcher([NotNull] params Func<IDictionary<string, string>, bool>[] funcs)
/// </param>
public RequestMessageCookieMatcher([NotNull] Func<IDictionary<string, string>, bool> func)
{ {
Check.NotNull(func, nameof(func)); Check.NotNull(funcs, nameof(funcs));
_cookieFunc = func; _cookieFuncs = funcs;
} }
/// <summary> /// <summary>
@@ -52,14 +60,14 @@ namespace WireMock.Matchers.Request
/// </returns> /// </returns>
public bool IsMatch(RequestMessage requestMessage) public bool IsMatch(RequestMessage requestMessage)
{ {
if (_cookieFunc != null) if (_cookieFuncs != null)
return _cookieFunc(requestMessage.Cookies); return _cookieFuncs.Any(cf => cf(requestMessage.Cookies));
if (requestMessage.Cookies == null) if (requestMessage.Cookies == null)
return false; return false;
string headerValue = requestMessage.Cookies[_name]; string headerValue = requestMessage.Cookies[Name];
return _matcher.IsMatch(headerValue); return Matchers.Any(m => m.IsMatch(headerValue));
} }
} }
} }
@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Validation; using WireMock.Validation;
@@ -10,20 +11,20 @@ namespace WireMock.Matchers.Request
/// </summary> /// </summary>
public class RequestMessageHeaderMatcher : IRequestMatcher public class RequestMessageHeaderMatcher : IRequestMatcher
{ {
/// <summary> private readonly Func<IDictionary<string, string>, bool>[] _headerFuncs;
/// The name.
/// </summary>
private readonly string _name;
/// <summary> /// <summary>
/// The matcher. /// The name
/// </summary> /// </summary>
private readonly IMatcher _matcher; public string Name { get; }
/// <summary> /// <summary>
/// The header function /// Gets the matchers.
/// </summary> /// </summary>
private readonly Func<IDictionary<string, string>, bool> _headerFunc; /// <value>
/// The matchers.
/// </value>
public IMatcher[] Matchers { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
@@ -36,20 +37,18 @@ namespace WireMock.Matchers.Request
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
Check.NotNull(pattern, nameof(pattern)); Check.NotNull(pattern, nameof(pattern));
_name = name; Name = name;
_matcher = new WildcardMatcher(pattern, ignoreCase); Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary> /// </summary>
/// <param name="func"> /// <param name="funcs">The funcs.</param>
/// The func. public RequestMessageHeaderMatcher([NotNull] params Func<IDictionary<string, string>, bool>[] funcs)
/// </param>
public RequestMessageHeaderMatcher([NotNull] Func<IDictionary<string, string>, bool> func)
{ {
Check.NotNull(func, nameof(func)); Check.NotNull(funcs, nameof(funcs));
_headerFunc = func; _headerFuncs = funcs;
} }
/// <summary> /// <summary>
@@ -61,14 +60,14 @@ namespace WireMock.Matchers.Request
/// </returns> /// </returns>
public bool IsMatch(RequestMessage requestMessage) public bool IsMatch(RequestMessage requestMessage)
{ {
if (_headerFunc != null) if (_headerFuncs != null)
return _headerFunc(requestMessage.Headers); return _headerFuncs.Any(hf => hf(requestMessage.Headers));
if (requestMessage.Headers == null) if (requestMessage.Headers == null)
return false; return false;
string headerValue = requestMessage.Headers[_name]; string headerValue = requestMessage.Headers[Name];
return _matcher.IsMatch(headerValue); return Matchers.Any(m => m.IsMatch(headerValue));
} }
} }
} }
@@ -12,17 +12,17 @@ namespace WireMock.Matchers.Request
/// </summary> /// </summary>
public class RequestMessageParamMatcher : IRequestMatcher public class RequestMessageParamMatcher : IRequestMatcher
{ {
/// <summary> private readonly Func<IDictionary<string, WireMockList<string>>, bool>[] _funcs;
/// The _key.
/// </summary>
private readonly string _key;
/// <summary> /// <summary>
/// The _values. /// The key
/// </summary> /// </summary>
private readonly IEnumerable<string> _values; public string Key { get; }
private readonly Func<IDictionary<string, WireMockList<string>>, bool> _func; /// <summary>
/// The values
/// </summary>
public IEnumerable<string> Values { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
@@ -38,20 +38,18 @@ namespace WireMock.Matchers.Request
Check.NotNull(key, nameof(key)); Check.NotNull(key, nameof(key));
Check.NotNull(values, nameof(values)); Check.NotNull(values, nameof(values));
_key = key; Key = key;
_values = values; Values = values;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary> /// </summary>
/// <param name="func"> /// <param name="funcs">The funcs.</param>
/// The func. public RequestMessageParamMatcher([NotNull] params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
/// </param>
public RequestMessageParamMatcher([NotNull] Func<IDictionary<string, WireMockList<string>>, bool> func)
{ {
Check.NotNull(func, nameof(func)); Check.NotNull(funcs, nameof(funcs));
_func = func; _funcs = funcs;
} }
/// <summary> /// <summary>
@@ -63,12 +61,11 @@ namespace WireMock.Matchers.Request
/// </returns> /// </returns>
public bool IsMatch(RequestMessage requestMessage) public bool IsMatch(RequestMessage requestMessage)
{ {
if (_func != null) if (_funcs != null)
{ return _funcs.Any(f => f(requestMessage.Query));
return _func(requestMessage.Query);
}
return requestMessage.GetParameter(_key).Intersect(_values).Count() == _values.Count(); var values = requestMessage.GetParameter(Key);
return values?.Intersect(Values).Count() == Values.Count();
} }
} }
} }
@@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Validation; using WireMock.Validation;
@@ -12,48 +14,39 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// The matcher. /// The matcher.
/// </summary> /// </summary>
private readonly string _path; public IReadOnlyList<IMatcher> Matchers { get; }
/// <summary> /// <summary>
/// The matcher. /// The path functions
/// </summary> /// </summary>
private readonly IMatcher _matcher; private readonly Func<string, bool>[] _pathFuncs;
/// <summary>
/// The path function
/// </summary>
private readonly Func<string, bool> _pathFunc;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="paths">The paths.</param>
public RequestMessagePathMatcher([NotNull] string path) public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).ToArray())
{ {
Check.NotNull(path, nameof(path));
_path = path;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matcher">The matcher.</param> /// <param name="matchers">The matchers.</param>
public RequestMessagePathMatcher([NotNull] IMatcher matcher) public RequestMessagePathMatcher([NotNull] params IMatcher[] matchers)
{ {
Check.NotNull(matcher, nameof(matcher)); Check.NotNull(matchers, nameof(matchers));
_matcher = matcher; Matchers = matchers;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary> /// </summary>
/// <param name="func"> /// <param name="funcs">The path functions.</param>
/// The path func. public RequestMessagePathMatcher([NotNull] params Func<string, bool>[] funcs)
/// </param>
public RequestMessagePathMatcher([NotNull] Func<string, bool> func)
{ {
Check.NotNull(func, nameof(func)); Check.NotNull(funcs, nameof(funcs));
_pathFunc = func; _pathFuncs = funcs;
} }
/// <summary> /// <summary>
@@ -65,14 +58,11 @@ namespace WireMock.Matchers.Request
/// </returns> /// </returns>
public bool IsMatch(RequestMessage requestMessage) public bool IsMatch(RequestMessage requestMessage)
{ {
if (_path != null) if (Matchers != null)
return string.CompareOrdinal(_path, requestMessage.Path) == 0; return Matchers.Any(matcher => matcher.IsMatch(requestMessage.Path));
if (_matcher != null) if (_pathFuncs != null)
return _matcher.IsMatch(requestMessage.Path); return _pathFuncs.Any(func => func(requestMessage.Path));
if (_pathFunc != null)
return _pathFunc(requestMessage.Path);
return false; return false;
} }
@@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Validation; using WireMock.Validation;
@@ -12,42 +14,39 @@ namespace WireMock.Matchers.Request
/// <summary> /// <summary>
/// The matcher. /// The matcher.
/// </summary> /// </summary>
private readonly IMatcher _matcher; public readonly IReadOnlyList<IMatcher> Matchers;
/// <summary> /// <summary>
/// The url function /// The url functions
/// </summary> /// </summary>
private readonly Func<string, bool> _urlFunc; private readonly Func<string, bool>[] _urlFuncs;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary> /// </summary>
/// <param name="url">The url.</param> /// <param name="urls">The urls.</param>
public RequestMessageUrlMatcher([NotNull] string url) : this(new WildcardMatcher(url)) public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).ToArray())
{ {
_matcher = new WildcardMatcher(url);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matcher">The matcher.</param> /// <param name="matchers">The matchers.</param>
public RequestMessageUrlMatcher([NotNull] IMatcher matcher) public RequestMessageUrlMatcher([NotNull] params IMatcher[] matchers)
{ {
Check.NotNull(matcher, nameof(matcher)); Check.NotNull(matchers, nameof(matchers));
_matcher = matcher; Matchers = matchers;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary> /// </summary>
/// <param name="func"> /// <param name="funcs">The url functions.</param>
/// The url func. public RequestMessageUrlMatcher([NotNull] params Func<string, bool>[] funcs)
/// </param>
public RequestMessageUrlMatcher([NotNull] Func<string, bool> func)
{ {
Check.NotNull(func, nameof(func)); Check.NotNull(funcs, nameof(funcs));
_urlFunc = func; _urlFuncs = funcs;
} }
/// <summary> /// <summary>
@@ -59,11 +58,11 @@ namespace WireMock.Matchers.Request
/// </returns> /// </returns>
public bool IsMatch(RequestMessage requestMessage) public bool IsMatch(RequestMessage requestMessage)
{ {
if (_matcher != null) if (Matchers != null)
return _matcher.IsMatch(requestMessage.Path); return Matchers.Any(matcher => matcher.IsMatch(requestMessage.Path));
if (_urlFunc != null) if (_urlFuncs != null)
return _urlFunc(requestMessage.Url); return _urlFuncs.Any(func => func(requestMessage.Url));
return false; return false;
} }
@@ -1,4 +1,5 @@
using JetBrains.Annotations; using System.Linq;
using JetBrains.Annotations;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Matchers.Request namespace WireMock.Matchers.Request
@@ -9,20 +10,20 @@ namespace WireMock.Matchers.Request
internal class RequestMessageVerbMatcher : IRequestMatcher internal class RequestMessageVerbMatcher : IRequestMatcher
{ {
/// <summary> /// <summary>
/// The _verb. /// The verbs
/// </summary> /// </summary>
private readonly string _verb; public string[] Verbs { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RequestMessageVerbMatcher"/> class. /// Initializes a new instance of the <see cref="RequestMessageVerbMatcher"/> class.
/// </summary> /// </summary>
/// <param name="verb"> /// <param name="verbs">
/// The verb. /// The verb.
/// </param> /// </param>
public RequestMessageVerbMatcher([NotNull] string verb) public RequestMessageVerbMatcher([NotNull] params string[] verbs)
{ {
Check.NotNull(verb, nameof(verb)); Check.NotNull(verbs, nameof(verbs));
_verb = verb.ToLower(); Verbs = verbs.Select(v => v.ToLower()).ToArray();
} }
/// <summary> /// <summary>
@@ -34,7 +35,7 @@ namespace WireMock.Matchers.Request
/// </returns> /// </returns>
public bool IsMatch(RequestMessage requestMessage) public bool IsMatch(RequestMessage requestMessage)
{ {
return requestMessage.Verb == _verb; return Verbs.Contains(requestMessage.Verb);
} }
} }
} }
+9
View File
@@ -37,6 +37,15 @@ namespace WireMock.Matchers
return MatchWildcardString(_pattern, input); return MatchWildcardString(_pattern, input);
} }
/// <summary>
/// Gets the pattern.
/// </summary>
/// <returns>Pattern</returns>
public string GetPattern()
{
return _pattern;
}
/// <summary> /// <summary>
/// Copy/paste from http://www.codeproject.com/Tips/57304/Use-wildcard-characters-and-to-compare-strings /// Copy/paste from http://www.codeproject.com/Tips/57304/Use-wildcard-characters-and-to-compare-strings
/// </summary> /// </summary>
+9
View File
@@ -49,5 +49,14 @@ namespace WireMock.Matchers
return false; return false;
} }
} }
/// <summary>
/// Gets the pattern.
/// </summary>
/// <returns>Pattern</returns>
public string GetPattern()
{
return _pattern;
}
} }
} }
@@ -22,9 +22,9 @@ namespace WireMock.RequestBuilders
/// <summary> /// <summary>
/// The with header. /// The with header.
/// </summary> /// </summary>
/// <param name="func">The headers func.</param> /// <param name="funcs">The headers funcs.</param>
/// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns> /// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns>
IHeadersAndCookiesRequestBuilder WithHeader([NotNull] params Func<IDictionary<string, string>, bool>[] func); IHeadersAndCookiesRequestBuilder WithHeader([NotNull] params Func<IDictionary<string, string>, bool>[] funcs);
/// <summary> /// <summary>
/// The with header. /// The with header.
@@ -38,8 +38,8 @@ namespace WireMock.RequestBuilders
/// <summary> /// <summary>
/// The with header. /// The with header.
/// </summary> /// </summary>
/// <param name="cookieFunc">The func.</param> /// <param name="cookieFuncs">The funcs.</param>
/// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns> /// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns>
IHeadersAndCookiesRequestBuilder WithCookie([NotNull] params Func<IDictionary<string, string>, bool>[] cookieFunc); IHeadersAndCookiesRequestBuilder WithCookie([NotNull] params Func<IDictionary<string, string>, bool>[] cookieFuncs);
} }
} }
@@ -28,12 +28,8 @@ namespace WireMock.RequestBuilders
/// <summary> /// <summary>
/// The with parameters. /// The with parameters.
/// </summary> /// </summary>
/// <param name="func"> /// <param name="funcs">The funcs.</param>
/// The func. /// <returns>The <see cref="IRequestMatcher"/>.</returns>
/// </param> IRequestMatcher WithParam([NotNull] params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs);
/// <returns>
/// The <see cref="IRequestMatcher"/>.
/// </returns>
IRequestMatcher WithParam([NotNull] Func<IDictionary<string, WireMockList<string>>, bool> func);
} }
} }
@@ -12,37 +12,37 @@ namespace WireMock.RequestBuilders
/// <summary> /// <summary>
/// The with url. /// The with url.
/// </summary> /// </summary>
/// <param name="matcher">The matcher.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
IUrlAndPathRequestBuilder WithUrl([NotNull] IMatcher matcher); IUrlAndPathRequestBuilder WithUrl([NotNull] params IMatcher[] matchers);
/// <summary> /// <summary>
/// The with url. /// The with url.
/// </summary> /// </summary>
/// <param name="url">The url.</param> /// <param name="urls">The urls.</param>
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
IUrlAndPathRequestBuilder WithUrl([NotNull] params string[] url); IUrlAndPathRequestBuilder WithUrl([NotNull] params string[] urls);
/// <summary> /// <summary>
/// The with url. /// The with url.
/// </summary> /// </summary>
/// <param name="func">The url func.</param> /// <param name="funcs">The url funcs.</param>
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
IUrlAndPathRequestBuilder WithUrl([NotNull] params Func<string, bool>[] func); IUrlAndPathRequestBuilder WithUrl([NotNull] params Func<string, bool>[] funcs);
/// <summary> /// <summary>
/// The with path. /// The with path.
/// </summary> /// </summary>
/// <param name="matcher">The matcher.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
IUrlAndPathRequestBuilder WithPath([NotNull] IMatcher matcher); IUrlAndPathRequestBuilder WithPath([NotNull] params IMatcher[] matchers);
/// <summary> /// <summary>
/// The with path. /// The with path.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="paths">The paths.</param>
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
IUrlAndPathRequestBuilder WithPath([NotNull] params string[] path); IUrlAndPathRequestBuilder WithPath([NotNull] params string[] paths);
/// <summary> /// <summary>
/// The with path. /// The with path.
+36 -35
View File
@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using WireMock.Matchers; using WireMock.Matchers;
using WireMock.Matchers.Request; using WireMock.Matchers.Request;
@@ -32,15 +33,34 @@ namespace WireMock.RequestBuilders
_requestMatchers = requestMatchers; _requestMatchers = requestMatchers;
} }
/// <summary>
/// Gets the request message matchers.
/// </summary>
/// <typeparam name="T">Type of IRequestMatcher</typeparam>
/// <returns>A List{T}</returns>
public IList<T> GetRequestMessageMatchers<T>() where T : IRequestMatcher
{
return new ReadOnlyCollection<T>(_requestMatchers.Where(rm => rm is T).Cast<T>().ToList());
}
/// <summary>
/// Gets the request message matcher.
/// </summary>
/// <typeparam name="T">Type of IRequestMatcher</typeparam>
/// <returns>A RequestMatcher</returns>
public T GetRequestMessageMatcher<T>() where T : IRequestMatcher
{
return _requestMatchers.Where(rm => rm is T).Cast<T>().FirstOrDefault();
}
/// <summary> /// <summary>
/// The with url. /// The with url.
/// </summary> /// </summary>
/// <param name="matcher">The matcher.</param> /// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
public IUrlAndPathRequestBuilder WithUrl(IMatcher matcher) public IUrlAndPathRequestBuilder WithUrl(params IMatcher[] matchers)
{ {
_requestMatchers.Add(new RequestMessageUrlMatcher(matcher)); _requestMatchers.Add(new RequestMessageUrlMatcher(matchers));
return this; return this;
} }
@@ -51,9 +71,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
public IUrlAndPathRequestBuilder WithUrl(params string[] urls) public IUrlAndPathRequestBuilder WithUrl(params string[] urls)
{ {
var or = new RequestMessageCompositeMatcher(urls.Select(url => new RequestMessageUrlMatcher(url)), CompositeMatcherType.Or); _requestMatchers.Add(new RequestMessageUrlMatcher(urls));
_requestMatchers.Add(or);
return this; return this;
} }
@@ -64,9 +82,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
public IUrlAndPathRequestBuilder WithUrl(params Func<string, bool>[] funcs) public IUrlAndPathRequestBuilder WithUrl(params Func<string, bool>[] funcs)
{ {
var or = new RequestMessageCompositeMatcher(funcs.Select(func => new RequestMessageUrlMatcher(func)), CompositeMatcherType.Or); _requestMatchers.Add(new RequestMessageUrlMatcher(funcs));
_requestMatchers.Add(or);
return this; return this;
} }
@@ -75,10 +91,9 @@ namespace WireMock.RequestBuilders
/// </summary> /// </summary>
/// <param name="matcher">The matcher.</param> /// <param name="matcher">The matcher.</param>
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
public IUrlAndPathRequestBuilder WithPath(IMatcher matcher) public IUrlAndPathRequestBuilder WithPath(params IMatcher[] matcher)
{ {
_requestMatchers.Add(new RequestMessagePathMatcher(matcher)); _requestMatchers.Add(new RequestMessagePathMatcher(matcher));
return this; return this;
} }
@@ -89,9 +104,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
public IUrlAndPathRequestBuilder WithPath(params string[] paths) public IUrlAndPathRequestBuilder WithPath(params string[] paths)
{ {
var or = new RequestMessageCompositeMatcher(paths.Select(path => new RequestMessageUrlMatcher(path)), CompositeMatcherType.Or); _requestMatchers.Add(new RequestMessagePathMatcher(paths));
_requestMatchers.Add(or);
return this; return this;
} }
@@ -102,9 +115,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns> /// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
public IUrlAndPathRequestBuilder WithPath(params Func<string, bool>[] funcs) public IUrlAndPathRequestBuilder WithPath(params Func<string, bool>[] funcs)
{ {
var or = new RequestMessageCompositeMatcher(funcs.Select(func => new RequestMessageUrlMatcher(func)), CompositeMatcherType.Or); _requestMatchers.Add(new RequestMessagePathMatcher(funcs));
_requestMatchers.Add(or);
return this; return this;
} }
@@ -192,9 +203,7 @@ namespace WireMock.RequestBuilders
/// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns> /// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns>
public IHeadersAndCookiesRequestBuilder UsingVerb(params string[] verbs) public IHeadersAndCookiesRequestBuilder UsingVerb(params string[] verbs)
{ {
var or = new RequestMessageCompositeMatcher(verbs.Select(verb => new RequestMessageVerbMatcher(verb)), CompositeMatcherType.Or); _requestMatchers.Add(new RequestMessageVerbMatcher(verbs));
_requestMatchers.Add(or);
return this; return this;
} }
@@ -292,15 +301,11 @@ namespace WireMock.RequestBuilders
/// <summary> /// <summary>
/// The with parameters. /// The with parameters.
/// </summary> /// </summary>
/// <param name="func"> /// <param name="funcs">The funcs.</param>
/// The func. /// <returns>The <see cref="IRequestMatcher"/>.</returns>
/// </param> public IRequestMatcher WithParam(params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
/// <returns>
/// The <see cref="IRequestMatcher"/>.
/// </returns>
public IRequestMatcher WithParam(Func<IDictionary<string, WireMockList<string>>, bool> func)
{ {
_requestMatchers.Add(new RequestMessageParamMatcher(func)); _requestMatchers.Add(new RequestMessageParamMatcher(funcs));
return this; return this;
} }
@@ -324,9 +329,7 @@ namespace WireMock.RequestBuilders
/// <returns></returns> /// <returns></returns>
public IHeadersAndCookiesRequestBuilder WithHeader(params Func<IDictionary<string, string>, bool>[] funcs) public IHeadersAndCookiesRequestBuilder WithHeader(params Func<IDictionary<string, string>, bool>[] funcs)
{ {
var or = new RequestMessageCompositeMatcher(funcs.Select(func => new RequestMessageHeaderMatcher(func)), CompositeMatcherType.Or); _requestMatchers.Add(new RequestMessageHeaderMatcher(funcs));
_requestMatchers.Add(or);
return this; return this;
} }
@@ -350,9 +353,7 @@ namespace WireMock.RequestBuilders
/// <returns></returns> /// <returns></returns>
public IHeadersAndCookiesRequestBuilder WithCookie(params Func<IDictionary<string, string>, bool>[] funcs) public IHeadersAndCookiesRequestBuilder WithCookie(params Func<IDictionary<string, string>, bool>[] funcs)
{ {
var or = new RequestMessageCompositeMatcher(funcs.Select(func => new RequestMessageCookieMatcher(func)), CompositeMatcherType.Or); _requestMatchers.Add(new RequestMessageCookieMatcher(funcs));
_requestMatchers.Add(or);
return this; return this;
} }
} }
+13 -10
View File
@@ -61,7 +61,7 @@ namespace WireMock
/// <param name="body">The body string.</param> /// <param name="body">The body string.</param>
/// <param name="headers">The headers.</param> /// <param name="headers">The headers.</param>
/// <param name="cookies">The cookies.</param> /// <param name="cookies">The cookies.</param>
public RequestMessage([NotNull] Uri url, [NotNull] string verb, [CanBeNull] byte[] bodyAsBytes, [CanBeNull] string body, [CanBeNull] IDictionary<string, string> headers = null, [CanBeNull] IDictionary<string, string> cookies = null) public RequestMessage([NotNull] Uri url, [NotNull] string verb, [CanBeNull] byte[] bodyAsBytes = null, [CanBeNull] string body = null, [CanBeNull] IDictionary<string, string> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
{ {
Check.NotNull(url, nameof(url)); Check.NotNull(url, nameof(url));
Check.NotNull(verb, nameof(verb)); Check.NotNull(verb, nameof(verb));
@@ -85,16 +85,19 @@ namespace WireMock
Query = query.Split('&').Aggregate( Query = query.Split('&').Aggregate(
new Dictionary<string, WireMockList<string>>(), new Dictionary<string, WireMockList<string>>(),
(dict, term) => (dict, term) =>
{
var parts = term.Split('=');
var key = parts[0];
if (!dict.ContainsKey(key))
{ {
var key = term.Split('=')[0]; dict.Add(key, new WireMockList<string>());
if (!dict.ContainsKey(key)) }
{
dict.Add(key, new WireMockList<string>());
}
dict[key].Add(term.Split('=')[1]); if (parts.Length == 2)
return dict; dict[key].Add(parts[1]);
});
return dict;
});
} }
} }
@@ -105,7 +108,7 @@ namespace WireMock
/// <returns>The query parameter.</returns> /// <returns>The query parameter.</returns>
public List<string> GetParameter(string key) public List<string> GetParameter(string key)
{ {
return Query.ContainsKey(key) ? Query[key] : new WireMockList<string>(); return Query.ContainsKey(key) ? Query[key] : null;
} }
} }
} }
@@ -5,7 +5,7 @@ namespace WireMock.ResponseBuilders
/// <summary> /// <summary>
/// The DelayResponseBuilder interface. /// The DelayResponseBuilder interface.
/// </summary> /// </summary>
public interface IDelayResponseBuilder : IProvideResponses public interface IDelayResponseBuilder : IResponseProvider
{ {
/// <summary> /// <summary>
/// The after delay. /// The after delay.
+44 -17
View File
@@ -14,19 +14,39 @@ namespace WireMock.ResponseBuilders
/// </summary> /// </summary>
public class Response : IResponseBuilder public class Response : IResponseBuilder
{ {
private readonly ResponseMessage _responseMessage;
private TimeSpan _delay = TimeSpan.Zero; private TimeSpan _delay = TimeSpan.Zero;
private bool _useTransformer; private bool _useTransformer;
/// <summary>
/// Gets the response message.
/// </summary>
/// <value>
/// The response message.
/// </value>
public ResponseMessage ResponseMessage { get; }
/// <summary>
/// Creates this instance.
/// </summary>
/// <param name="responseMessage">ResponseMessage</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
[PublicAPI]
public static IResponseBuilder Create([CanBeNull] ResponseMessage responseMessage = null)
{
var message = responseMessage ?? new ResponseMessage { StatusCode = (int)HttpStatusCode.OK };
return new Response(message);
}
/// <summary> /// <summary>
/// Creates this instance. /// Creates this instance.
/// </summary> /// </summary>
/// <returns>A <see cref="IResponseBuilder"/>.</returns> /// <returns>A <see cref="IResponseBuilder"/>.</returns>
[PublicAPI] [PublicAPI]
public static IResponseBuilder Create([CanBeNull] ResponseMessage responseMessage = null) public static IResponseBuilder Create([NotNull] Func<ResponseMessage> func)
{ {
var message = responseMessage ?? new ResponseMessage { StatusCode = (int) HttpStatusCode.OK }; Check.NotNull(func, nameof(func));
return new Response(message);
return new Response(func());
} }
/// <summary> /// <summary>
@@ -37,7 +57,7 @@ namespace WireMock.ResponseBuilders
/// </param> /// </param>
private Response(ResponseMessage responseMessage) private Response(ResponseMessage responseMessage)
{ {
_responseMessage = responseMessage; ResponseMessage = responseMessage;
} }
/// <summary> /// <summary>
@@ -48,7 +68,7 @@ namespace WireMock.ResponseBuilders
[PublicAPI] [PublicAPI]
public IHeadersResponseBuilder WithStatusCode(int code) public IHeadersResponseBuilder WithStatusCode(int code)
{ {
_responseMessage.StatusCode = code; ResponseMessage.StatusCode = code;
return this; return this;
} }
@@ -60,7 +80,7 @@ namespace WireMock.ResponseBuilders
[PublicAPI] [PublicAPI]
public IHeadersResponseBuilder WithStatusCode(HttpStatusCode code) public IHeadersResponseBuilder WithStatusCode(HttpStatusCode code)
{ {
return WithStatusCode((int) code); return WithStatusCode((int)code);
} }
/// <summary> /// <summary>
@@ -70,7 +90,7 @@ namespace WireMock.ResponseBuilders
[PublicAPI] [PublicAPI]
public IHeadersResponseBuilder WithSuccess() public IHeadersResponseBuilder WithSuccess()
{ {
return WithStatusCode((int) HttpStatusCode.OK); return WithStatusCode((int)HttpStatusCode.OK);
} }
/// <summary> /// <summary>
@@ -93,7 +113,7 @@ namespace WireMock.ResponseBuilders
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
_responseMessage.AddHeader(name, value); ResponseMessage.AddHeader(name, value);
return this; return this;
} }
@@ -106,7 +126,7 @@ namespace WireMock.ResponseBuilders
{ {
Check.NotNull(body, nameof(body)); Check.NotNull(body, nameof(body));
_responseMessage.Body = body; ResponseMessage.Body = body;
return this; return this;
} }
@@ -120,7 +140,7 @@ namespace WireMock.ResponseBuilders
{ {
Check.NotNull(bodyAsbase64, nameof(bodyAsbase64)); Check.NotNull(bodyAsbase64, nameof(bodyAsbase64));
_responseMessage.Body = (encoding ?? Encoding.UTF8).GetString(Convert.FromBase64String(bodyAsbase64)); ResponseMessage.Body = (encoding ?? Encoding.UTF8).GetString(Convert.FromBase64String(bodyAsbase64));
return this; return this;
} }
@@ -143,7 +163,7 @@ namespace WireMock.ResponseBuilders
/// The delay. /// The delay.
/// </param> /// </param>
/// <returns> /// <returns>
/// The <see cref="IProvideResponses"/>. /// The <see cref="IResponseProvider"/>.
/// </returns> /// </returns>
public IResponseBuilder WithDelay(TimeSpan delay) public IResponseBuilder WithDelay(TimeSpan delay)
{ {
@@ -162,29 +182,36 @@ namespace WireMock.ResponseBuilders
/// </returns> /// </returns>
public async Task<ResponseMessage> ProvideResponse(RequestMessage requestMessage) public async Task<ResponseMessage> ProvideResponse(RequestMessage requestMessage)
{ {
ResponseMessage responseMessage;
if (_useTransformer) if (_useTransformer)
{ {
responseMessage = new ResponseMessage { StatusCode = ResponseMessage.StatusCode };
var template = new { request = requestMessage }; var template = new { request = requestMessage };
// Body // Body
var templateBody = Handlebars.Compile(_responseMessage.Body); var templateBody = Handlebars.Compile(ResponseMessage.Body);
_responseMessage.Body = templateBody(template); responseMessage.Body = templateBody(template);
// Headers // Headers
var newHeaders = new Dictionary<string, string>(); var newHeaders = new Dictionary<string, string>();
foreach (var header in _responseMessage.Headers) foreach (var header in ResponseMessage.Headers)
{ {
var templateHeaderKey = Handlebars.Compile(header.Key); var templateHeaderKey = Handlebars.Compile(header.Key);
var templateHeaderValue = Handlebars.Compile(header.Value); var templateHeaderValue = Handlebars.Compile(header.Value);
newHeaders.Add(templateHeaderKey(template), templateHeaderValue(template)); newHeaders.Add(templateHeaderKey(template), templateHeaderValue(template));
} }
_responseMessage.Headers = newHeaders; responseMessage.Headers = newHeaders;
}
else
{
responseMessage = ResponseMessage;
} }
await Task.Delay(_delay); await Task.Delay(_delay);
return _responseMessage; return responseMessage;
} }
} }
} }
+2 -2
View File
@@ -3,8 +3,8 @@
/// <summary> /// <summary>
/// The registration callback. /// The registration callback.
/// </summary> /// </summary>
/// <param name="route"> /// <param name="mapping">
/// The route. /// The route.
/// </param> /// </param>
public delegate void RegistrationCallback(Route route); public delegate void RegistrationCallback(Mapping mapping);
} }
@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
using WireMock.Admin;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
namespace WireMock.Server
{
/// <summary>
/// The fluent mock server.
/// </summary>
public partial class FluentMockServer
{
private void InitAdmin()
{
Given(Request.Create().WithUrl("/__admin/mappings").UsingGet()).RespondWith(new DynamicResponseProvider(MappingsGet));
}
private ResponseMessage MappingsGet()
{
var result = new List<MappingModel>();
foreach (var mapping in Mappings.Where(m => !(m.Provider is DynamicResponseProvider)))
{
var request = (Request) mapping.RequestMatcher;
var urlMatchers = request.GetRequestMessageMatchers<RequestMessageUrlMatcher>();
var headerMatchers = request.GetRequestMessageMatchers<RequestMessageHeaderMatcher>();
var cookieMatchers = request.GetRequestMessageMatchers<RequestMessageCookieMatcher>();
var paramsMatchers = request.GetRequestMessageMatchers<RequestMessageParamMatcher>();
var bodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
var verbMatcher = request.GetRequestMessageMatcher<RequestMessageVerbMatcher>();
var response = (Response) mapping.Provider;
var model = new MappingModel
{
Guid = Guid.NewGuid(),
Request = new RequestModel
{
Url = new UrlModel
{
Matchers = urlMatchers != null ? Map(urlMatchers.Where(m => m.Matchers != null).SelectMany(m => m.Matchers)) : null
},
Verbs = verbMatcher != null ? verbMatcher.Verbs : new [] { "any" },
Headers = headerMatchers?.Select(hm => new HeaderModel
{
Name = hm.Name,
Matchers = Map(hm.Matchers)
}).ToList(),
Cookies = cookieMatchers?.Select(hm => new CookieModel
{
Name = hm.Name,
Matchers = Map(hm.Matchers)
}).ToList(),
Params = paramsMatchers?.Select(hm => new ParamModel
{
Name = hm.Key,
Values = hm.Values?.ToList()
}).ToList(),
Body = new BodyModel
{
Matcher = bodyMatcher != null ? Map(bodyMatcher.Matcher) : null
}
},
Response = new ResponseModel
{
StatusCode = response.ResponseMessage.StatusCode,
Headers = response.ResponseMessage.Headers,
Body = response.ResponseMessage.Body
}
};
result.Add(model);
}
return ToJson(result);
}
private IList<MatcherModel> Map([CanBeNull] IEnumerable<IMatcher> matchers)
{
return matchers?.Select(Map).Where(x => x != null).ToList();
}
private MatcherModel Map([CanBeNull] IMatcher matcher)
{
if (matcher == null)
return null;
return new MatcherModel
{
Name = matcher.GetType().Name,
Pattern = matcher.GetPattern()
};
}
private ResponseMessage ToJson<T>(T result)
{
return new ResponseMessage
{
Body = JsonConvert.SerializeObject(result, Formatting.Indented),
StatusCode = 200,
Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
};
}
}
}
+46 -45
View File
@@ -16,7 +16,7 @@ namespace WireMock.Server
/// <summary> /// <summary>
/// The fluent mock server. /// The fluent mock server.
/// </summary> /// </summary>
public class FluentMockServer public partial class FluentMockServer
{ {
/// <summary> /// <summary>
/// The _http server. /// The _http server.
@@ -24,9 +24,9 @@ namespace WireMock.Server
private readonly TinyHttpServer _httpServer; private readonly TinyHttpServer _httpServer;
/// <summary> /// <summary>
/// The _routes. /// The _mappings.
/// </summary> /// </summary>
private readonly IList<Route> _routes = new List<Route>(); private readonly IList<Mapping> _mappings = new List<Mapping>();
/// <summary> /// <summary>
/// The _request logs. /// The _request logs.
@@ -75,13 +75,13 @@ namespace WireMock.Server
/// <summary> /// <summary>
/// Gets the routes. /// Gets the routes.
/// </summary> /// </summary>
public IEnumerable<Route> Routes public IEnumerable<Mapping> Mappings
{ {
get get
{ {
lock (((ICollection)_routes).SyncRoot) lock (((ICollection)_mappings).SyncRoot)
{ {
return new ReadOnlyCollection<Route>(_routes); return new ReadOnlyCollection<Mapping>(_mappings);
} }
} }
} }
@@ -89,15 +89,9 @@ namespace WireMock.Server
/// <summary> /// <summary>
/// Start this FluentMockServer. /// Start this FluentMockServer.
/// </summary> /// </summary>
/// <param name="port"> /// <param name="port">The port.</param>
/// The port. /// <param name="ssl">The SSL support.</param>
/// </param> /// <returns>The <see cref="FluentMockServer"/>.</returns>
/// <param name="ssl">
/// The SSL support.
/// </param>
/// <returns>
/// The <see cref="FluentMockServer"/>.
/// </returns>
[PublicAPI] [PublicAPI]
public static FluentMockServer Start(int port = 0, bool ssl = false) public static FluentMockServer Start(int port = 0, bool ssl = false)
{ {
@@ -106,24 +100,37 @@ namespace WireMock.Server
if (port == 0) if (port == 0)
port = Ports.FindFreeTcpPort(); port = Ports.FindFreeTcpPort();
return new FluentMockServer(port, ssl); return new FluentMockServer(false, port, ssl);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FluentMockServer"/> class, and starts the server. /// Start this FluentMockServer with the admin interface.
/// </summary> /// </summary>
/// <param name="port"> /// <param name="port">The port.</param>
/// The port. /// <param name="ssl">The SSL support.</param>
/// </param> /// <returns>The <see cref="FluentMockServer"/>.</returns>
/// <param name="ssl"> [PublicAPI]
/// The SSL support. public static FluentMockServer StartWithAdminInterface(int port = 0, bool ssl = false)
/// </param> {
private FluentMockServer(int port, bool ssl) Check.Condition(port, p => p >= 0, nameof(port));
if (port == 0)
port = Ports.FindFreeTcpPort();
return new FluentMockServer(true, port, ssl);
}
private FluentMockServer(bool startAdmin, int port, bool ssl)
{ {
string protocol = ssl ? "https" : "http"; string protocol = ssl ? "https" : "http";
_httpServer = new TinyHttpServer(protocol + "://localhost:" + port + "/", HandleRequest); _httpServer = new TinyHttpServer(protocol + "://localhost:" + port + "/", HandleRequestAsync);
Port = port; Port = port;
_httpServer.Start(); _httpServer.Start();
if (startAdmin)
{
InitAdmin();
}
} }
/// <summary> /// <summary>
@@ -144,9 +151,9 @@ namespace WireMock.Server
_requestLogs.Clear(); _requestLogs.Clear();
} }
lock (((ICollection)_routes).SyncRoot) lock (((ICollection)_mappings).SyncRoot)
{ {
_routes.Clear(); _mappings.Clear();
} }
} }
@@ -184,28 +191,24 @@ namespace WireMock.Server
/// <summary> /// <summary>
/// The given. /// The given.
/// </summary> /// </summary>
/// <param name="requestMatcher"> /// <param name="requestMatcher">The request matcher.</param>
/// The request matcher. /// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
/// </param>
/// <returns>
/// The <see cref="IRespondWithAProvider"/>.
/// </returns>
public IRespondWithAProvider Given(IRequestMatcher requestMatcher) public IRespondWithAProvider Given(IRequestMatcher requestMatcher)
{ {
return new RespondWithAProvider(RegisterRoute, requestMatcher); return new RespondWithAProvider(RegisterMapping, requestMatcher);
} }
/// <summary> /// <summary>
/// The register route. /// The register mapping.
/// </summary> /// </summary>
/// <param name="route"> /// <param name="mapping">
/// The route. /// The mapping.
/// </param> /// </param>
private void RegisterRoute(Route route) private void RegisterMapping(Mapping mapping)
{ {
lock (((ICollection)_routes).SyncRoot) lock (((ICollection)_mappings).SyncRoot)
{ {
_routes.Add(route); _mappings.Add(mapping);
} }
} }
@@ -226,10 +229,8 @@ namespace WireMock.Server
/// <summary> /// <summary>
/// The handle request. /// The handle request.
/// </summary> /// </summary>
/// <param name="ctx"> /// <param name="ctx">The HttpListenerContext.</param>
/// The context. private async void HandleRequestAsync(HttpListenerContext ctx)
/// </param>
private async void HandleRequest(HttpListenerContext ctx)
{ {
lock (_syncRoot) lock (_syncRoot)
{ {
@@ -241,7 +242,7 @@ namespace WireMock.Server
try try
{ {
var targetRoute = _routes.FirstOrDefault(route => route.IsRequestHandled(request)); var targetRoute = _mappings.FirstOrDefault(route => route.IsRequestHandled(request));
if (targetRoute == null) if (targetRoute == null)
{ {
ctx.Response.StatusCode = 404; ctx.Response.StatusCode = 404;
+1 -1
View File
@@ -11,6 +11,6 @@
/// <param name="provider"> /// <param name="provider">
/// The provider. /// The provider.
/// </param> /// </param>
void RespondWith(IProvideResponses provider); void RespondWith(IResponseProvider provider);
} }
} }
+7 -11
View File
@@ -15,21 +15,17 @@ namespace WireMock.Server
/// <summary> /// <summary>
/// The _request matcher. /// The _request matcher.
/// </summary> /// </summary>
private readonly IRequestMatcher _requestSpec; private readonly IRequestMatcher _requestMatcher;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class. /// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
/// </summary> /// </summary>
/// <param name="registrationCallback"> /// <param name="registrationCallback">The registration callback.</param>
/// The registration callback. /// <param name="requestMatcher">The request matcher.</param>
/// </param> public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestMatcher)
/// <param name="requestSpec">
/// The request matcher.
/// </param>
public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestSpec)
{ {
_registrationCallback = registrationCallback; _registrationCallback = registrationCallback;
_requestSpec = requestSpec; _requestMatcher = requestMatcher;
} }
/// <summary> /// <summary>
@@ -38,9 +34,9 @@ namespace WireMock.Server
/// <param name="provider"> /// <param name="provider">
/// The provider. /// The provider.
/// </param> /// </param>
public void RespondWith(IProvideResponses provider) public void RespondWith(IResponseProvider provider)
{ {
_registrationCallback(new Route(_requestSpec, provider)); _registrationCallback(new Mapping(_requestMatcher, provider));
} }
} }
} }
+8
View File
@@ -17,6 +17,14 @@ namespace WireMock.Util
{ {
} }
/// <summary>
/// Initializes a new instance of the <see cref="WireMockList{T}"/> class.
/// </summary>
/// <param name="collection">The collection whose elements are copied to the new list.</param>
public WireMockList(params T[] collection) : base(collection)
{
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WireMockList{T}"/> class. /// Initializes a new instance of the <see cref="WireMockList{T}"/> class.
/// </summary> /// </summary>
+2 -1
View File
@@ -6,13 +6,14 @@
"packOptions": { "packOptions": {
"summary": "Lightweigth Http Mocking Server for .Net, inspired by WireMock from the Java landscape.", "summary": "Lightweigth Http Mocking Server for .Net, inspired by WireMock from the Java landscape.",
"tags": [ "system", "linq", "dynamic", "core" ], "tags": [ "tdd", "mock", "http", "wiremock", "test" ],
"owners": [ "Stef Heyenrath" ], "owners": [ "Stef Heyenrath" ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/StefH/WireMock.Net" "url": "https://github.com/StefH/WireMock.Net"
}, },
"projectUrl": "https://github.com/StefH/WireMock.Net", "projectUrl": "https://github.com/StefH/WireMock.Net",
"iconUrl": "https://raw.githubusercontent.com/StefH/WireMock.Net/master/WireMock.Net-Logo.png",
"licenseUrl": "https://raw.githubusercontent.com/StefH/WireMock.Net/master/LICENSE", "licenseUrl": "https://raw.githubusercontent.com/StefH/WireMock.Net/master/LICENSE",
"releaseNotes": "First version" "releaseNotes": "First version"
}, },
@@ -30,7 +30,7 @@ namespace WireMock.Net.Tests
_server.Given(Request.Create().WithUrl("/foo2").UsingGet()) _server.Given(Request.Create().WithUrl("/foo2").UsingGet())
.RespondWith(Response.Create().WithStatusCode(202).WithBody("2")); .RespondWith(Response.Create().WithStatusCode(202).WithBody("2"));
var routes = _server.Routes; var routes = _server.Mappings;
Check.That(routes).HasSize(2); Check.That(routes).HasSize(2);
Check.That(routes.First().RequestMatcher).IsNotNull(); Check.That(routes.First().RequestMatcher).IsNotNull();
@@ -12,12 +12,10 @@ namespace WireMock.Net.Tests
public void Should_handle_empty_query() public void Should_handle_empty_query()
{ {
// given // given
string bodyAsString = "whatever"; var request = new RequestMessage(new Uri("http://localhost/foo"), "POST");
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", body, bodyAsString);
// then // then
Check.That(request.GetParameter("foo")).IsEmpty(); Check.That(request.GetParameter("not_there")).IsNull();
} }
[Test] [Test]
+28 -2
View File
@@ -40,6 +40,19 @@ namespace WireMock.Net.Tests
Check.That(requestBuilder.IsMatch(request2)).IsTrue(); Check.That(requestBuilder.IsMatch(request2)).IsTrue();
} }
[Test]
public void Should_specify_requests_matching_given_urlFuncs()
{
// given
var spec = Request.Create().WithUrl(url => url.EndsWith("/foo"));
// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "blabla");
// then
Check.That(spec.IsMatch(request)).IsTrue();
}
[Test] [Test]
public void Should_specify_requests_matching_given_url_prefix() public void Should_specify_requests_matching_given_url_prefix()
{ {
@@ -394,7 +407,7 @@ namespace WireMock.Net.Tests
} }
[Test] [Test]
public void Should_specify_requests_matching_given_params() public void Should_specify_requests_matching_given_param()
{ {
// given // given
var spec = Request.Create().WithPath("/foo").WithParam("bar", "1", "2"); var spec = Request.Create().WithPath("/foo").WithParam("bar", "1", "2");
@@ -409,7 +422,20 @@ namespace WireMock.Net.Tests
} }
[Test] [Test]
public void Should_specify_requests_matching_given_params_func() public void Should_specify_requests_matching_given_paramNoValue()
{
// given
var spec = Request.Create().WithPath("/foo").WithParam("bar");
// when
var request = new RequestMessage(new Uri("http://localhost/foo?bar"), "PUT");
// then
Check.That(spec.IsMatch(request)).IsTrue();
}
[Test]
public void Should_specify_requests_matching_given_param_func()
{ {
// given // given
var spec = Request.Create().WithPath("/foo").UsingAnyVerb().WithParam(p => p.ContainsKey("bar")); var spec = Request.Create().WithPath("/foo").UsingAnyVerb().WithParam(p => p.ContainsKey("bar"));