diff --git a/examples/WireMock.Net.ConsoleApplication/Program.cs b/examples/WireMock.Net.ConsoleApplication/Program.cs
index 99f5a9e2..fa1df233 100644
--- a/examples/WireMock.Net.ConsoleApplication/Program.cs
+++ b/examples/WireMock.Net.ConsoleApplication/Program.cs
@@ -5,7 +5,6 @@ using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
-
namespace WireMock.Net.ConsoleApplication
{
static class Program
@@ -14,9 +13,9 @@ namespace WireMock.Net.ConsoleApplication
{
int 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);
server
@@ -24,17 +23,17 @@ namespace WireMock.Net.ConsoleApplication
.RespondWith(Response.Create()
.WithStatusCode(200)
.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
server
- .Given(Request.Create().WithUrl("/*").UsingGet())
+ .Given(Request.Create().WithUrl("/*").UsingGet().WithParam("start"))
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithHeader("Transformed-Postman-Token", "token is {{request.headers.Postman-Token}}")
- .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]}}""")
+ .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]}}""")
.WithTransformer()
.WithDelay(TimeSpan.FromMilliseconds(100))
);
@@ -47,7 +46,7 @@ namespace WireMock.Net.ConsoleApplication
.WithBody(@"{ ""result"": ""data posted with FUNC 201""}"));
server
- .Given(Request.Create().WithUrl("/data", "/ax").UsingPost())
+ .Given(Request.Create().WithUrl("/data", "/ax").UsingPost().WithHeader("Content-Type", "application/json*"))
.RespondWith(Response.Create()
.WithStatusCode(201)
.WithHeader("Content-Type", "application/json")
@@ -60,6 +59,13 @@ namespace WireMock.Net.ConsoleApplication
.WithHeader("Content-Type", "application/json")
.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
.Given(Request.Create().WithUrl("/data").UsingDelete())
.RespondWith(Response.Create()
@@ -67,6 +73,11 @@ namespace WireMock.Net.ConsoleApplication
.WithHeader("Content-Type", "application/json")
.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.ReadKey();
diff --git a/src/WireMock/Admin/BodyModel.cs b/src/WireMock/Admin/BodyModel.cs
new file mode 100644
index 00000000..ac0dfd0e
--- /dev/null
+++ b/src/WireMock/Admin/BodyModel.cs
@@ -0,0 +1,16 @@
+namespace WireMock.Admin
+{
+ ///
+ /// Body Model
+ ///
+ public class BodyModel
+ {
+ ///
+ /// Gets or sets the matcher.
+ ///
+ ///
+ /// The matcher.
+ ///
+ public MatcherModel Matcher { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/Admin/CookieModel.cs b/src/WireMock/Admin/CookieModel.cs
new file mode 100644
index 00000000..68807650
--- /dev/null
+++ b/src/WireMock/Admin/CookieModel.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace WireMock.Admin
+{
+ ///
+ /// Cookie Model
+ ///
+ public class CookieModel
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ ///
+ /// The name.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the matchers.
+ ///
+ ///
+ /// The matchers.
+ ///
+ public IList Matchers { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/Admin/FuncModel.cs b/src/WireMock/Admin/FuncModel.cs
new file mode 100644
index 00000000..ecef8070
--- /dev/null
+++ b/src/WireMock/Admin/FuncModel.cs
@@ -0,0 +1,7 @@
+//namespace WireMock.Admin
+//{
+// public class FuncModel
+// {
+// public string Name { get; set; }
+// }
+//}
\ No newline at end of file
diff --git a/src/WireMock/Admin/HeaderModel.cs b/src/WireMock/Admin/HeaderModel.cs
new file mode 100644
index 00000000..262c699f
--- /dev/null
+++ b/src/WireMock/Admin/HeaderModel.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace WireMock.Admin
+{
+ ///
+ /// Header Model
+ ///
+ public class HeaderModel
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ ///
+ /// The name.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the matchers.
+ ///
+ ///
+ /// The matchers.
+ ///
+ public IList Matchers { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/Admin/MappingModel.cs b/src/WireMock/Admin/MappingModel.cs
new file mode 100644
index 00000000..3b5ea4ca
--- /dev/null
+++ b/src/WireMock/Admin/MappingModel.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace WireMock.Admin
+{
+ ///
+ /// MappingModel
+ ///
+ public class MappingModel
+ {
+ ///
+ /// Gets or sets the unique identifier.
+ ///
+ ///
+ /// The unique identifier.
+ ///
+ public Guid Guid { get; set; }
+
+ ///
+ /// Gets or sets the request.
+ ///
+ ///
+ /// The request.
+ ///
+ public RequestModel Request { get; set; }
+
+ ///
+ /// Gets or sets the response.
+ ///
+ ///
+ /// The response.
+ ///
+ public ResponseModel Response { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/Admin/MatcherModel.cs b/src/WireMock/Admin/MatcherModel.cs
new file mode 100644
index 00000000..56f5106d
--- /dev/null
+++ b/src/WireMock/Admin/MatcherModel.cs
@@ -0,0 +1,24 @@
+namespace WireMock.Admin
+{
+ ///
+ /// MatcherModel
+ ///
+ public class MatcherModel
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ ///
+ /// The name.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the pattern.
+ ///
+ ///
+ /// The pattern.
+ ///
+ public string Pattern { get; set; }
+ }
+}
diff --git a/src/WireMock/Admin/ParamModel.cs b/src/WireMock/Admin/ParamModel.cs
new file mode 100644
index 00000000..e4c85bc1
--- /dev/null
+++ b/src/WireMock/Admin/ParamModel.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace WireMock.Admin
+{
+ ///
+ /// Param Model
+ ///
+ public class ParamModel
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ ///
+ /// The name.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the values.
+ ///
+ ///
+ /// The values.
+ ///
+ public IList Values { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/Admin/RequestModel.cs b/src/WireMock/Admin/RequestModel.cs
new file mode 100644
index 00000000..cdc2b08d
--- /dev/null
+++ b/src/WireMock/Admin/RequestModel.cs
@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+
+namespace WireMock.Admin
+{
+ ///
+ /// RequestModel
+ ///
+ public class RequestModel
+ {
+ ///
+ /// Gets or sets the URL.
+ ///
+ ///
+ /// The URL.
+ ///
+ public UrlModel Url { get; set; }
+
+ ///
+ /// The verbs
+ ///
+ public string[] Verbs { get; set; }
+
+ ///
+ /// Gets or sets the Headers.
+ ///
+ ///
+ /// The Headers.
+ ///
+ public IList Headers { get; set; }
+
+ ///
+ /// Gets or sets the Cookies.
+ ///
+ ///
+ /// The Cookies.
+ ///
+ public IList Cookies { get; set; }
+
+ ///
+ /// Gets or sets the Params.
+ ///
+ ///
+ /// The Headers.
+ ///
+ public IList Params { get; set; }
+
+ ///
+ /// Gets or sets the body.
+ ///
+ ///
+ /// The body.
+ ///
+ public BodyModel Body { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/Admin/ResponseModel.cs b/src/WireMock/Admin/ResponseModel.cs
new file mode 100644
index 00000000..cd7551dd
--- /dev/null
+++ b/src/WireMock/Admin/ResponseModel.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace WireMock.Admin
+{
+ ///
+ /// ResponseModel
+ ///
+ public class ResponseModel
+ {
+ ///
+ /// Gets or sets the HTTP status.
+ ///
+ ///
+ /// The HTTP status.
+ ///
+ public int StatusCode { get; set; }
+
+ ///
+ /// Gets or sets the body.
+ ///
+ ///
+ /// The body.
+ ///
+ public string Body { get; set; }
+
+ ///
+ /// Gets or sets the headers.
+ ///
+ ///
+ /// The headers.
+ ///
+ public IDictionary Headers { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/Admin/UrlModel.cs b/src/WireMock/Admin/UrlModel.cs
new file mode 100644
index 00000000..77164271
--- /dev/null
+++ b/src/WireMock/Admin/UrlModel.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+namespace WireMock.Admin
+{
+ ///
+ /// UrlModel
+ ///
+ public class UrlModel
+ {
+ ///
+ /// Gets or sets the matchers.
+ ///
+ ///
+ /// The matchers.
+ ///
+ public IList Matchers { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/DynamicResponseProvider.cs b/src/WireMock/DynamicResponseProvider.cs
new file mode 100644
index 00000000..9fd64afa
--- /dev/null
+++ b/src/WireMock/DynamicResponseProvider.cs
@@ -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 _responseMessageFunc;
+
+ public DynamicResponseProvider([NotNull] Func responseMessageFunc)
+ {
+ Check.NotNull(responseMessageFunc, nameof(responseMessageFunc));
+
+ _responseMessageFunc = responseMessageFunc;
+ }
+
+ public Task ProvideResponse(RequestMessage requestMessage)
+ {
+ return Task.FromResult(_responseMessageFunc());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/IProvideResponses.cs b/src/WireMock/IResponseProvider.cs
similarity index 53%
rename from src/WireMock/IProvideResponses.cs
rename to src/WireMock/IResponseProvider.cs
index 055d5ec3..7c785ee2 100644
--- a/src/WireMock/IProvideResponses.cs
+++ b/src/WireMock/IResponseProvider.cs
@@ -1,17 +1,11 @@
-using System.Diagnostics.CodeAnalysis;
-using System.Threading.Tasks;
-
-[module:
- SuppressMessage("StyleCop.CSharp.DocumentationRules",
- "SA1633:FileMustHaveHeader",
- Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
+using System.Threading.Tasks;
namespace WireMock
{
///
- /// The ProvideResponses interface.
+ /// The Response Provider interface.
///
- public interface IProvideResponses
+ public interface IResponseProvider
{
///
/// The provide response.
diff --git a/src/WireMock/Route.cs b/src/WireMock/Mapping.cs
similarity index 82%
rename from src/WireMock/Route.cs
rename to src/WireMock/Mapping.cs
index 474b2fab..4ae6d86a 100644
--- a/src/WireMock/Route.cs
+++ b/src/WireMock/Mapping.cs
@@ -6,24 +6,24 @@ namespace WireMock
///
/// The route.
///
- public class Route
+ public class Mapping
{
///
- /// The _request matcher.
+ /// The Request matcher.
///
public IRequestMatcher RequestMatcher { get; }
///
- /// The _provider.
+ /// The Provider.
///
- public IProvideResponses Provider { get; }
+ public IResponseProvider Provider { get; }
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The request matcher.
/// The provider.
- public Route(IRequestMatcher requestMatcher, IProvideResponses provider)
+ public Mapping(IRequestMatcher requestMatcher, IResponseProvider provider)
{
RequestMatcher = requestMatcher;
Provider = provider;
diff --git a/src/WireMock/Matchers/IMatcher.cs b/src/WireMock/Matchers/IMatcher.cs
index 398f2508..073043e7 100644
--- a/src/WireMock/Matchers/IMatcher.cs
+++ b/src/WireMock/Matchers/IMatcher.cs
@@ -13,5 +13,11 @@
/// true if the specified input is match; otherwise, false.
///
bool IsMatch(string input);
+
+ ///
+ /// Gets the pattern.
+ ///
+ /// Pattern
+ string GetPattern();
}
}
\ No newline at end of file
diff --git a/src/WireMock/Matchers/JSONPathMatcher.cs b/src/WireMock/Matchers/JSONPathMatcher.cs
index 6fa93bcf..97f85004 100644
--- a/src/WireMock/Matchers/JSONPathMatcher.cs
+++ b/src/WireMock/Matchers/JSONPathMatcher.cs
@@ -48,5 +48,14 @@ namespace WireMock.Matchers
return false;
}
}
+
+ ///
+ /// Gets the pattern.
+ ///
+ /// Pattern
+ public string GetPattern()
+ {
+ return _pattern;
+ }
}
}
\ No newline at end of file
diff --git a/src/WireMock/Matchers/RegexMatcher.cs b/src/WireMock/Matchers/RegexMatcher.cs
index ad634bc0..6f4c9ea0 100644
--- a/src/WireMock/Matchers/RegexMatcher.cs
+++ b/src/WireMock/Matchers/RegexMatcher.cs
@@ -11,6 +11,7 @@ namespace WireMock.Matchers
///
public class RegexMatcher : IMatcher
{
+ private readonly string _pattern;
private readonly Regex _expression;
///
@@ -21,7 +22,8 @@ namespace WireMock.Matchers
{
Check.NotNull(pattern, nameof(pattern));
- _expression = new Regex(pattern, RegexOptions.Compiled);
+ _pattern = pattern;
+ _expression = new Regex(_pattern, RegexOptions.Compiled);
}
///
@@ -45,5 +47,14 @@ namespace WireMock.Matchers
return false;
}
}
+
+ ///
+ /// Gets the pattern.
+ ///
+ /// Pattern
+ public string GetPattern()
+ {
+ return _pattern;
+ }
}
}
\ No newline at end of file
diff --git a/src/WireMock/Matchers/Request/RequestMessageBodyMatcher.cs b/src/WireMock/Matchers/Request/RequestMessageBodyMatcher.cs
index c67e74ff..70b3e82b 100644
--- a/src/WireMock/Matchers/Request/RequestMessageBodyMatcher.cs
+++ b/src/WireMock/Matchers/Request/RequestMessageBodyMatcher.cs
@@ -19,11 +19,6 @@ namespace WireMock.Matchers.Request
///
private readonly byte[] _bodyData;
- ///
- /// The matcher.
- ///
- private readonly IMatcher _matcher;
-
///
/// The body function
///
@@ -34,6 +29,11 @@ namespace WireMock.Matchers.Request
///
private readonly Func _bodyDataFunc;
+ ///
+ /// The matcher.
+ ///
+ public readonly IMatcher Matcher;
+
///
/// Initializes a new instance of the class.
///
@@ -91,7 +91,7 @@ namespace WireMock.Matchers.Request
public RequestMessageBodyMatcher([NotNull] IMatcher matcher)
{
Check.NotNull(matcher, nameof(matcher));
- _matcher = matcher;
+ Matcher = matcher;
}
///
@@ -103,8 +103,8 @@ namespace WireMock.Matchers.Request
///
public bool IsMatch(RequestMessage requestMessage)
{
- if (_matcher != null)
- return _matcher.IsMatch(requestMessage.Body);
+ if (Matcher != null)
+ return Matcher.IsMatch(requestMessage.Body);
if (_body != null)
return requestMessage.Body == _body;
diff --git a/src/WireMock/Matchers/Request/RequestMessageCompositeMatcher.cs b/src/WireMock/Matchers/Request/RequestMessageCompositeMatcher.cs
index 6b40aaa2..c7c94f9a 100644
--- a/src/WireMock/Matchers/Request/RequestMessageCompositeMatcher.cs
+++ b/src/WireMock/Matchers/Request/RequestMessageCompositeMatcher.cs
@@ -1,13 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
+using WireMock.Validation;
namespace WireMock.Matchers.Request
{
///
/// The composite request matcher.
///
- public class RequestMessageCompositeMatcher : IRequestMatcher
+ public abstract class RequestMessageCompositeMatcher : IRequestMatcher
{
private readonly CompositeMatcherType _type;
@@ -17,15 +18,17 @@ namespace WireMock.Matchers.Request
///
/// The request matchers.
///
- public IEnumerable RequestMatchers { get; }
+ private IEnumerable RequestMatchers { get; }
///
/// Initializes a new instance of the class.
///
/// The request matchers.
/// The CompositeMatcherType type (Defaults to 'And')
- public RequestMessageCompositeMatcher([NotNull] IEnumerable requestMatchers, CompositeMatcherType type = CompositeMatcherType.And)
+ protected RequestMessageCompositeMatcher([NotNull] IEnumerable requestMatchers, CompositeMatcherType type = CompositeMatcherType.And)
{
+ Check.NotNull(requestMatchers, nameof(requestMatchers));
+
_type = type;
RequestMatchers = requestMatchers;
}
@@ -37,11 +40,11 @@ namespace WireMock.Matchers.Request
///
/// true if the specified RequestMessage is match; otherwise, false.
///
- public bool IsMatch(RequestMessage requestMessage)
+ public virtual bool IsMatch(RequestMessage requestMessage)
{
return _type == CompositeMatcherType.And ?
- RequestMatchers.All(spec => spec.IsMatch(requestMessage)) :
- RequestMatchers.Any(spec => spec.IsMatch(requestMessage));
+ RequestMatchers.All(matcher => matcher.IsMatch(requestMessage)) :
+ RequestMatchers.Any(matcher => matcher.IsMatch(requestMessage));
}
}
}
\ No newline at end of file
diff --git a/src/WireMock/Matchers/Request/RequestMessageCookieMatcher.cs b/src/WireMock/Matchers/Request/RequestMessageCookieMatcher.cs
index 690b5d3b..ce277113 100644
--- a/src/WireMock/Matchers/Request/RequestMessageCookieMatcher.cs
+++ b/src/WireMock/Matchers/Request/RequestMessageCookieMatcher.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using JetBrains.Annotations;
using WireMock.Validation;
@@ -10,12 +11,21 @@ namespace WireMock.Matchers.Request
///
public class RequestMessageCookieMatcher : IRequestMatcher
{
- private readonly string _name;
+ private readonly Func, bool>[] _cookieFuncs;
- private readonly IMatcher _matcher;
-
- private readonly Func, bool> _cookieFunc;
+ ///
+ /// The name
+ ///
+ public string Name { get; }
+ ///
+ /// Gets the matchers.
+ ///
+ ///
+ /// The matchers.
+ ///
+ public IMatcher[] Matchers { get; }
+
///
/// Initializes a new instance of the class.
///
@@ -27,20 +37,18 @@ namespace WireMock.Matchers.Request
Check.NotNull(name, nameof(name));
Check.NotNull(pattern, nameof(pattern));
- _name = name;
- _matcher = new WildcardMatcher(pattern, ignoreCase);
+ Name = name;
+ Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
}
///
/// Initializes a new instance of the class.
///
- ///
- /// The func.
- ///
- public RequestMessageCookieMatcher([NotNull] Func, bool> func)
+ /// The funcs.
+ public RequestMessageCookieMatcher([NotNull] params Func, bool>[] funcs)
{
- Check.NotNull(func, nameof(func));
- _cookieFunc = func;
+ Check.NotNull(funcs, nameof(funcs));
+ _cookieFuncs = funcs;
}
///
@@ -52,14 +60,14 @@ namespace WireMock.Matchers.Request
///
public bool IsMatch(RequestMessage requestMessage)
{
- if (_cookieFunc != null)
- return _cookieFunc(requestMessage.Cookies);
+ if (_cookieFuncs != null)
+ return _cookieFuncs.Any(cf => cf(requestMessage.Cookies));
if (requestMessage.Cookies == null)
return false;
- string headerValue = requestMessage.Cookies[_name];
- return _matcher.IsMatch(headerValue);
+ string headerValue = requestMessage.Cookies[Name];
+ return Matchers.Any(m => m.IsMatch(headerValue));
}
}
}
\ No newline at end of file
diff --git a/src/WireMock/Matchers/Request/RequestMessageHeaderMatcher.cs b/src/WireMock/Matchers/Request/RequestMessageHeaderMatcher.cs
index 13fbf77f..702b57e2 100644
--- a/src/WireMock/Matchers/Request/RequestMessageHeaderMatcher.cs
+++ b/src/WireMock/Matchers/Request/RequestMessageHeaderMatcher.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using JetBrains.Annotations;
using WireMock.Validation;
@@ -10,20 +11,20 @@ namespace WireMock.Matchers.Request
///
public class RequestMessageHeaderMatcher : IRequestMatcher
{
- ///
- /// The name.
- ///
- private readonly string _name;
+ private readonly Func, bool>[] _headerFuncs;
///
- /// The matcher.
+ /// The name
///
- private readonly IMatcher _matcher;
+ public string Name { get; }
///
- /// The header function
+ /// Gets the matchers.
///
- private readonly Func, bool> _headerFunc;
+ ///
+ /// The matchers.
+ ///
+ public IMatcher[] Matchers { get; }
///
/// Initializes a new instance of the class.
@@ -36,20 +37,18 @@ namespace WireMock.Matchers.Request
Check.NotNull(name, nameof(name));
Check.NotNull(pattern, nameof(pattern));
- _name = name;
- _matcher = new WildcardMatcher(pattern, ignoreCase);
+ Name = name;
+ Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
}
///
/// Initializes a new instance of the class.
///
- ///
- /// The func.
- ///
- public RequestMessageHeaderMatcher([NotNull] Func, bool> func)
+ /// The funcs.
+ public RequestMessageHeaderMatcher([NotNull] params Func, bool>[] funcs)
{
- Check.NotNull(func, nameof(func));
- _headerFunc = func;
+ Check.NotNull(funcs, nameof(funcs));
+ _headerFuncs = funcs;
}
///
@@ -61,14 +60,14 @@ namespace WireMock.Matchers.Request
///
public bool IsMatch(RequestMessage requestMessage)
{
- if (_headerFunc != null)
- return _headerFunc(requestMessage.Headers);
+ if (_headerFuncs != null)
+ return _headerFuncs.Any(hf => hf(requestMessage.Headers));
if (requestMessage.Headers == null)
return false;
- string headerValue = requestMessage.Headers[_name];
- return _matcher.IsMatch(headerValue);
+ string headerValue = requestMessage.Headers[Name];
+ return Matchers.Any(m => m.IsMatch(headerValue));
}
}
}
\ No newline at end of file
diff --git a/src/WireMock/Matchers/Request/RequestMessageParamMatcher.cs b/src/WireMock/Matchers/Request/RequestMessageParamMatcher.cs
index 8197fb02..eebb1574 100644
--- a/src/WireMock/Matchers/Request/RequestMessageParamMatcher.cs
+++ b/src/WireMock/Matchers/Request/RequestMessageParamMatcher.cs
@@ -12,17 +12,17 @@ namespace WireMock.Matchers.Request
///
public class RequestMessageParamMatcher : IRequestMatcher
{
- ///
- /// The _key.
- ///
- private readonly string _key;
+ private readonly Func>, bool>[] _funcs;
///
- /// The _values.
+ /// The key
///
- private readonly IEnumerable _values;
+ public string Key { get; }
- private readonly Func>, bool> _func;
+ ///
+ /// The values
+ ///
+ public IEnumerable Values { get; }
///
/// Initializes a new instance of the class.
@@ -38,20 +38,18 @@ namespace WireMock.Matchers.Request
Check.NotNull(key, nameof(key));
Check.NotNull(values, nameof(values));
- _key = key;
- _values = values;
+ Key = key;
+ Values = values;
}
///
/// Initializes a new instance of the class.
///
- ///
- /// The func.
- ///
- public RequestMessageParamMatcher([NotNull] Func>, bool> func)
+ /// The funcs.
+ public RequestMessageParamMatcher([NotNull] params Func>, bool>[] funcs)
{
- Check.NotNull(func, nameof(func));
- _func = func;
+ Check.NotNull(funcs, nameof(funcs));
+ _funcs = funcs;
}
///
@@ -63,12 +61,11 @@ namespace WireMock.Matchers.Request
///
public bool IsMatch(RequestMessage requestMessage)
{
- if (_func != null)
- {
- return _func(requestMessage.Query);
- }
+ if (_funcs != null)
+ return _funcs.Any(f => f(requestMessage.Query));
- return requestMessage.GetParameter(_key).Intersect(_values).Count() == _values.Count();
+ var values = requestMessage.GetParameter(Key);
+ return values?.Intersect(Values).Count() == Values.Count();
}
}
}
\ No newline at end of file
diff --git a/src/WireMock/Matchers/Request/RequestMessagePathMatcher.cs b/src/WireMock/Matchers/Request/RequestMessagePathMatcher.cs
index 42fbfbc0..fe711ee9 100644
--- a/src/WireMock/Matchers/Request/RequestMessagePathMatcher.cs
+++ b/src/WireMock/Matchers/Request/RequestMessagePathMatcher.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using JetBrains.Annotations;
using WireMock.Validation;
@@ -12,48 +14,39 @@ namespace WireMock.Matchers.Request
///
/// The matcher.
///
- private readonly string _path;
+ public IReadOnlyList Matchers { get; }
///
- /// The matcher.
+ /// The path functions
///
- private readonly IMatcher _matcher;
-
- ///
- /// The path function
- ///
- private readonly Func _pathFunc;
+ private readonly Func[] _pathFuncs;
///
/// Initializes a new instance of the class.
///
- /// The path.
- public RequestMessagePathMatcher([NotNull] string path)
+ /// The paths.
+ public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).ToArray())
{
- Check.NotNull(path, nameof(path));
- _path = path;
}
///
/// Initializes a new instance of the class.
///
- /// The matcher.
- public RequestMessagePathMatcher([NotNull] IMatcher matcher)
+ /// The matchers.
+ public RequestMessagePathMatcher([NotNull] params IMatcher[] matchers)
{
- Check.NotNull(matcher, nameof(matcher));
- _matcher = matcher;
+ Check.NotNull(matchers, nameof(matchers));
+ Matchers = matchers;
}
///
/// Initializes a new instance of the class.
///
- ///
- /// The path func.
- ///
- public RequestMessagePathMatcher([NotNull] Func func)
+ /// The path functions.
+ public RequestMessagePathMatcher([NotNull] params Func[] funcs)
{
- Check.NotNull(func, nameof(func));
- _pathFunc = func;
+ Check.NotNull(funcs, nameof(funcs));
+ _pathFuncs = funcs;
}
///
@@ -65,14 +58,11 @@ namespace WireMock.Matchers.Request
///
public bool IsMatch(RequestMessage requestMessage)
{
- if (_path != null)
- return string.CompareOrdinal(_path, requestMessage.Path) == 0;
+ if (Matchers != null)
+ return Matchers.Any(matcher => matcher.IsMatch(requestMessage.Path));
- if (_matcher != null)
- return _matcher.IsMatch(requestMessage.Path);
-
- if (_pathFunc != null)
- return _pathFunc(requestMessage.Path);
+ if (_pathFuncs != null)
+ return _pathFuncs.Any(func => func(requestMessage.Path));
return false;
}
diff --git a/src/WireMock/Matchers/Request/RequestMessageUrlMatcher.cs b/src/WireMock/Matchers/Request/RequestMessageUrlMatcher.cs
index cc0c26c9..3afde1b3 100644
--- a/src/WireMock/Matchers/Request/RequestMessageUrlMatcher.cs
+++ b/src/WireMock/Matchers/Request/RequestMessageUrlMatcher.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using JetBrains.Annotations;
using WireMock.Validation;
@@ -12,42 +14,39 @@ namespace WireMock.Matchers.Request
///
/// The matcher.
///
- private readonly IMatcher _matcher;
+ public readonly IReadOnlyList Matchers;
///
- /// The url function
+ /// The url functions
///
- private readonly Func _urlFunc;
+ private readonly Func[] _urlFuncs;
///
/// Initializes a new instance of the class.
///
- /// The url.
- public RequestMessageUrlMatcher([NotNull] string url) : this(new WildcardMatcher(url))
+ /// The urls.
+ public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).ToArray())
{
- _matcher = new WildcardMatcher(url);
}
///
/// Initializes a new instance of the class.
///
- /// The matcher.
- public RequestMessageUrlMatcher([NotNull] IMatcher matcher)
+ /// The matchers.
+ public RequestMessageUrlMatcher([NotNull] params IMatcher[] matchers)
{
- Check.NotNull(matcher, nameof(matcher));
- _matcher = matcher;
+ Check.NotNull(matchers, nameof(matchers));
+ Matchers = matchers;
}
///
/// Initializes a new instance of the class.
///
- ///
- /// The url func.
- ///
- public RequestMessageUrlMatcher([NotNull] Func func)
+ /// The url functions.
+ public RequestMessageUrlMatcher([NotNull] params Func[] funcs)
{
- Check.NotNull(func, nameof(func));
- _urlFunc = func;
+ Check.NotNull(funcs, nameof(funcs));
+ _urlFuncs = funcs;
}
///
@@ -59,11 +58,11 @@ namespace WireMock.Matchers.Request
///
public bool IsMatch(RequestMessage requestMessage)
{
- if (_matcher != null)
- return _matcher.IsMatch(requestMessage.Path);
+ if (Matchers != null)
+ return Matchers.Any(matcher => matcher.IsMatch(requestMessage.Path));
- if (_urlFunc != null)
- return _urlFunc(requestMessage.Url);
+ if (_urlFuncs != null)
+ return _urlFuncs.Any(func => func(requestMessage.Url));
return false;
}
diff --git a/src/WireMock/Matchers/Request/RequestMessageVerbMatcher.cs b/src/WireMock/Matchers/Request/RequestMessageVerbMatcher.cs
index 826f8617..7ef8d01b 100644
--- a/src/WireMock/Matchers/Request/RequestMessageVerbMatcher.cs
+++ b/src/WireMock/Matchers/Request/RequestMessageVerbMatcher.cs
@@ -1,4 +1,5 @@
-using JetBrains.Annotations;
+using System.Linq;
+using JetBrains.Annotations;
using WireMock.Validation;
namespace WireMock.Matchers.Request
@@ -9,20 +10,20 @@ namespace WireMock.Matchers.Request
internal class RequestMessageVerbMatcher : IRequestMatcher
{
///
- /// The _verb.
+ /// The verbs
///
- private readonly string _verb;
+ public string[] Verbs { get; }
///
/// Initializes a new instance of the class.
///
- ///
+ ///
/// The verb.
///
- public RequestMessageVerbMatcher([NotNull] string verb)
+ public RequestMessageVerbMatcher([NotNull] params string[] verbs)
{
- Check.NotNull(verb, nameof(verb));
- _verb = verb.ToLower();
+ Check.NotNull(verbs, nameof(verbs));
+ Verbs = verbs.Select(v => v.ToLower()).ToArray();
}
///
@@ -34,7 +35,7 @@ namespace WireMock.Matchers.Request
///
public bool IsMatch(RequestMessage requestMessage)
{
- return requestMessage.Verb == _verb;
+ return Verbs.Contains(requestMessage.Verb);
}
}
}
\ No newline at end of file
diff --git a/src/WireMock/Matchers/WildcardMatcher.cs b/src/WireMock/Matchers/WildcardMatcher.cs
index 2db63b75..1ff651be 100644
--- a/src/WireMock/Matchers/WildcardMatcher.cs
+++ b/src/WireMock/Matchers/WildcardMatcher.cs
@@ -37,6 +37,15 @@ namespace WireMock.Matchers
return MatchWildcardString(_pattern, input);
}
+ ///
+ /// Gets the pattern.
+ ///
+ /// Pattern
+ public string GetPattern()
+ {
+ return _pattern;
+ }
+
///
/// Copy/paste from http://www.codeproject.com/Tips/57304/Use-wildcard-characters-and-to-compare-strings
///
diff --git a/src/WireMock/Matchers/XPathMatcher.cs b/src/WireMock/Matchers/XPathMatcher.cs
index caa6b7b9..b1a92c91 100644
--- a/src/WireMock/Matchers/XPathMatcher.cs
+++ b/src/WireMock/Matchers/XPathMatcher.cs
@@ -49,5 +49,14 @@ namespace WireMock.Matchers
return false;
}
}
+
+ ///
+ /// Gets the pattern.
+ ///
+ /// Pattern
+ public string GetPattern()
+ {
+ return _pattern;
+ }
}
}
\ No newline at end of file
diff --git a/src/WireMock/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs b/src/WireMock/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs
index bfae8478..4c98d83a 100644
--- a/src/WireMock/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs
+++ b/src/WireMock/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs
@@ -22,9 +22,9 @@ namespace WireMock.RequestBuilders
///
/// The with header.
///
- /// The headers func.
+ /// The headers funcs.
/// The .
- IHeadersAndCookiesRequestBuilder WithHeader([NotNull] params Func, bool>[] func);
+ IHeadersAndCookiesRequestBuilder WithHeader([NotNull] params Func, bool>[] funcs);
///
/// The with header.
@@ -38,8 +38,8 @@ namespace WireMock.RequestBuilders
///
/// The with header.
///
- /// The func.
+ /// The funcs.
/// The .
- IHeadersAndCookiesRequestBuilder WithCookie([NotNull] params Func, bool>[] cookieFunc);
+ IHeadersAndCookiesRequestBuilder WithCookie([NotNull] params Func, bool>[] cookieFuncs);
}
}
\ No newline at end of file
diff --git a/src/WireMock/RequestBuilders/IParamsRequestBuilder.cs b/src/WireMock/RequestBuilders/IParamsRequestBuilder.cs
index b445688b..3c6b563c 100644
--- a/src/WireMock/RequestBuilders/IParamsRequestBuilder.cs
+++ b/src/WireMock/RequestBuilders/IParamsRequestBuilder.cs
@@ -28,12 +28,8 @@ namespace WireMock.RequestBuilders
///
/// The with parameters.
///
- ///
- /// The func.
- ///
- ///
- /// The .
- ///
- IRequestMatcher WithParam([NotNull] Func>, bool> func);
+ /// The funcs.
+ /// The .
+ IRequestMatcher WithParam([NotNull] params Func>, bool>[] funcs);
}
}
\ No newline at end of file
diff --git a/src/WireMock/RequestBuilders/IUrlAndPathRequestBuilder.cs b/src/WireMock/RequestBuilders/IUrlAndPathRequestBuilder.cs
index bc500fb5..0f93c4e6 100644
--- a/src/WireMock/RequestBuilders/IUrlAndPathRequestBuilder.cs
+++ b/src/WireMock/RequestBuilders/IUrlAndPathRequestBuilder.cs
@@ -12,37 +12,37 @@ namespace WireMock.RequestBuilders
///
/// The with url.
///
- /// The matcher.
+ /// The matchers.
/// The .
- IUrlAndPathRequestBuilder WithUrl([NotNull] IMatcher matcher);
+ IUrlAndPathRequestBuilder WithUrl([NotNull] params IMatcher[] matchers);
///
/// The with url.
///
- /// The url.
+ /// The urls.
/// The .
- IUrlAndPathRequestBuilder WithUrl([NotNull] params string[] url);
+ IUrlAndPathRequestBuilder WithUrl([NotNull] params string[] urls);
///
/// The with url.
///
- /// The url func.
+ /// The url funcs.
/// The .
- IUrlAndPathRequestBuilder WithUrl([NotNull] params Func[] func);
+ IUrlAndPathRequestBuilder WithUrl([NotNull] params Func[] funcs);
///
/// The with path.
///
- /// The matcher.
+ /// The matchers.
/// The .
- IUrlAndPathRequestBuilder WithPath([NotNull] IMatcher matcher);
+ IUrlAndPathRequestBuilder WithPath([NotNull] params IMatcher[] matchers);
///
/// The with path.
///
- /// The path.
+ /// The paths.
/// The .
- IUrlAndPathRequestBuilder WithPath([NotNull] params string[] path);
+ IUrlAndPathRequestBuilder WithPath([NotNull] params string[] paths);
///
/// The with path.
diff --git a/src/WireMock/RequestBuilders/Request.cs b/src/WireMock/RequestBuilders/Request.cs
index ea9f97c9..249ce344 100644
--- a/src/WireMock/RequestBuilders/Request.cs
+++ b/src/WireMock/RequestBuilders/Request.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Linq;
using WireMock.Matchers;
using WireMock.Matchers.Request;
@@ -32,15 +33,34 @@ namespace WireMock.RequestBuilders
_requestMatchers = requestMatchers;
}
+ ///
+ /// Gets the request message matchers.
+ ///
+ /// Type of IRequestMatcher
+ /// A List{T}
+ public IList GetRequestMessageMatchers() where T : IRequestMatcher
+ {
+ return new ReadOnlyCollection(_requestMatchers.Where(rm => rm is T).Cast().ToList());
+ }
+
+ ///
+ /// Gets the request message matcher.
+ ///
+ /// Type of IRequestMatcher
+ /// A RequestMatcher
+ public T GetRequestMessageMatcher() where T : IRequestMatcher
+ {
+ return _requestMatchers.Where(rm => rm is T).Cast().FirstOrDefault();
+ }
+
///
/// The with url.
///
- /// The matcher.
+ /// The matchers.
/// The .
- public IUrlAndPathRequestBuilder WithUrl(IMatcher matcher)
+ public IUrlAndPathRequestBuilder WithUrl(params IMatcher[] matchers)
{
- _requestMatchers.Add(new RequestMessageUrlMatcher(matcher));
-
+ _requestMatchers.Add(new RequestMessageUrlMatcher(matchers));
return this;
}
@@ -51,9 +71,7 @@ namespace WireMock.RequestBuilders
/// The .
public IUrlAndPathRequestBuilder WithUrl(params string[] urls)
{
- var or = new RequestMessageCompositeMatcher(urls.Select(url => new RequestMessageUrlMatcher(url)), CompositeMatcherType.Or);
- _requestMatchers.Add(or);
-
+ _requestMatchers.Add(new RequestMessageUrlMatcher(urls));
return this;
}
@@ -64,9 +82,7 @@ namespace WireMock.RequestBuilders
/// The .
public IUrlAndPathRequestBuilder WithUrl(params Func[] funcs)
{
- var or = new RequestMessageCompositeMatcher(funcs.Select(func => new RequestMessageUrlMatcher(func)), CompositeMatcherType.Or);
- _requestMatchers.Add(or);
-
+ _requestMatchers.Add(new RequestMessageUrlMatcher(funcs));
return this;
}
@@ -75,10 +91,9 @@ namespace WireMock.RequestBuilders
///
/// The matcher.
/// The .
- public IUrlAndPathRequestBuilder WithPath(IMatcher matcher)
+ public IUrlAndPathRequestBuilder WithPath(params IMatcher[] matcher)
{
_requestMatchers.Add(new RequestMessagePathMatcher(matcher));
-
return this;
}
@@ -89,9 +104,7 @@ namespace WireMock.RequestBuilders
/// The .
public IUrlAndPathRequestBuilder WithPath(params string[] paths)
{
- var or = new RequestMessageCompositeMatcher(paths.Select(path => new RequestMessageUrlMatcher(path)), CompositeMatcherType.Or);
- _requestMatchers.Add(or);
-
+ _requestMatchers.Add(new RequestMessagePathMatcher(paths));
return this;
}
@@ -102,9 +115,7 @@ namespace WireMock.RequestBuilders
/// The .
public IUrlAndPathRequestBuilder WithPath(params Func[] funcs)
{
- var or = new RequestMessageCompositeMatcher(funcs.Select(func => new RequestMessageUrlMatcher(func)), CompositeMatcherType.Or);
- _requestMatchers.Add(or);
-
+ _requestMatchers.Add(new RequestMessagePathMatcher(funcs));
return this;
}
@@ -192,9 +203,7 @@ namespace WireMock.RequestBuilders
/// The .
public IHeadersAndCookiesRequestBuilder UsingVerb(params string[] verbs)
{
- var or = new RequestMessageCompositeMatcher(verbs.Select(verb => new RequestMessageVerbMatcher(verb)), CompositeMatcherType.Or);
- _requestMatchers.Add(or);
-
+ _requestMatchers.Add(new RequestMessageVerbMatcher(verbs));
return this;
}
@@ -292,15 +301,11 @@ namespace WireMock.RequestBuilders
///
/// The with parameters.
///
- ///
- /// The func.
- ///
- ///
- /// The .
- ///
- public IRequestMatcher WithParam(Func>, bool> func)
+ /// The funcs.
+ /// The .
+ public IRequestMatcher WithParam(params Func>, bool>[] funcs)
{
- _requestMatchers.Add(new RequestMessageParamMatcher(func));
+ _requestMatchers.Add(new RequestMessageParamMatcher(funcs));
return this;
}
@@ -324,9 +329,7 @@ namespace WireMock.RequestBuilders
///
public IHeadersAndCookiesRequestBuilder WithHeader(params Func, bool>[] funcs)
{
- var or = new RequestMessageCompositeMatcher(funcs.Select(func => new RequestMessageHeaderMatcher(func)), CompositeMatcherType.Or);
- _requestMatchers.Add(or);
-
+ _requestMatchers.Add(new RequestMessageHeaderMatcher(funcs));
return this;
}
@@ -350,9 +353,7 @@ namespace WireMock.RequestBuilders
///
public IHeadersAndCookiesRequestBuilder WithCookie(params Func, bool>[] funcs)
{
- var or = new RequestMessageCompositeMatcher(funcs.Select(func => new RequestMessageCookieMatcher(func)), CompositeMatcherType.Or);
- _requestMatchers.Add(or);
-
+ _requestMatchers.Add(new RequestMessageCookieMatcher(funcs));
return this;
}
}
diff --git a/src/WireMock/RequestMessage.cs b/src/WireMock/RequestMessage.cs
index 39429eec..e9117f59 100644
--- a/src/WireMock/RequestMessage.cs
+++ b/src/WireMock/RequestMessage.cs
@@ -61,7 +61,7 @@ namespace WireMock
/// The body string.
/// The headers.
/// The cookies.
- public RequestMessage([NotNull] Uri url, [NotNull] string verb, [CanBeNull] byte[] bodyAsBytes, [CanBeNull] string body, [CanBeNull] IDictionary headers = null, [CanBeNull] IDictionary cookies = null)
+ public RequestMessage([NotNull] Uri url, [NotNull] string verb, [CanBeNull] byte[] bodyAsBytes = null, [CanBeNull] string body = null, [CanBeNull] IDictionary headers = null, [CanBeNull] IDictionary cookies = null)
{
Check.NotNull(url, nameof(url));
Check.NotNull(verb, nameof(verb));
@@ -85,16 +85,19 @@ namespace WireMock
Query = query.Split('&').Aggregate(
new Dictionary>(),
(dict, term) =>
+ {
+ var parts = term.Split('=');
+ var key = parts[0];
+ if (!dict.ContainsKey(key))
{
- var key = term.Split('=')[0];
- if (!dict.ContainsKey(key))
- {
- dict.Add(key, new WireMockList());
- }
+ dict.Add(key, new WireMockList());
+ }
- dict[key].Add(term.Split('=')[1]);
- return dict;
- });
+ if (parts.Length == 2)
+ dict[key].Add(parts[1]);
+
+ return dict;
+ });
}
}
@@ -105,7 +108,7 @@ namespace WireMock
/// The query parameter.
public List GetParameter(string key)
{
- return Query.ContainsKey(key) ? Query[key] : new WireMockList();
+ return Query.ContainsKey(key) ? Query[key] : null;
}
}
}
\ No newline at end of file
diff --git a/src/WireMock/ResponseBuilders/IDelayResponseBuilder.cs b/src/WireMock/ResponseBuilders/IDelayResponseBuilder.cs
index 11b48917..03804a15 100644
--- a/src/WireMock/ResponseBuilders/IDelayResponseBuilder.cs
+++ b/src/WireMock/ResponseBuilders/IDelayResponseBuilder.cs
@@ -5,7 +5,7 @@ namespace WireMock.ResponseBuilders
///
/// The DelayResponseBuilder interface.
///
- public interface IDelayResponseBuilder : IProvideResponses
+ public interface IDelayResponseBuilder : IResponseProvider
{
///
/// The after delay.
diff --git a/src/WireMock/ResponseBuilders/Response.cs b/src/WireMock/ResponseBuilders/Response.cs
index ff7095c0..98b5d2b2 100644
--- a/src/WireMock/ResponseBuilders/Response.cs
+++ b/src/WireMock/ResponseBuilders/Response.cs
@@ -14,19 +14,39 @@ namespace WireMock.ResponseBuilders
///
public class Response : IResponseBuilder
{
- private readonly ResponseMessage _responseMessage;
private TimeSpan _delay = TimeSpan.Zero;
private bool _useTransformer;
+ ///
+ /// Gets the response message.
+ ///
+ ///
+ /// The response message.
+ ///
+ public ResponseMessage ResponseMessage { get; }
+
+ ///
+ /// Creates this instance.
+ ///
+ /// ResponseMessage
+ /// A .
+ [PublicAPI]
+ public static IResponseBuilder Create([CanBeNull] ResponseMessage responseMessage = null)
+ {
+ var message = responseMessage ?? new ResponseMessage { StatusCode = (int)HttpStatusCode.OK };
+ return new Response(message);
+ }
+
///
/// Creates this instance.
///
/// A .
[PublicAPI]
- public static IResponseBuilder Create([CanBeNull] ResponseMessage responseMessage = null)
+ public static IResponseBuilder Create([NotNull] Func func)
{
- var message = responseMessage ?? new ResponseMessage { StatusCode = (int) HttpStatusCode.OK };
- return new Response(message);
+ Check.NotNull(func, nameof(func));
+
+ return new Response(func());
}
///
@@ -37,7 +57,7 @@ namespace WireMock.ResponseBuilders
///
private Response(ResponseMessage responseMessage)
{
- _responseMessage = responseMessage;
+ ResponseMessage = responseMessage;
}
///
@@ -48,7 +68,7 @@ namespace WireMock.ResponseBuilders
[PublicAPI]
public IHeadersResponseBuilder WithStatusCode(int code)
{
- _responseMessage.StatusCode = code;
+ ResponseMessage.StatusCode = code;
return this;
}
@@ -60,7 +80,7 @@ namespace WireMock.ResponseBuilders
[PublicAPI]
public IHeadersResponseBuilder WithStatusCode(HttpStatusCode code)
{
- return WithStatusCode((int) code);
+ return WithStatusCode((int)code);
}
///
@@ -70,7 +90,7 @@ namespace WireMock.ResponseBuilders
[PublicAPI]
public IHeadersResponseBuilder WithSuccess()
{
- return WithStatusCode((int) HttpStatusCode.OK);
+ return WithStatusCode((int)HttpStatusCode.OK);
}
///
@@ -93,7 +113,7 @@ namespace WireMock.ResponseBuilders
{
Check.NotNull(name, nameof(name));
- _responseMessage.AddHeader(name, value);
+ ResponseMessage.AddHeader(name, value);
return this;
}
@@ -106,7 +126,7 @@ namespace WireMock.ResponseBuilders
{
Check.NotNull(body, nameof(body));
- _responseMessage.Body = body;
+ ResponseMessage.Body = body;
return this;
}
@@ -120,7 +140,7 @@ namespace WireMock.ResponseBuilders
{
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;
}
@@ -143,7 +163,7 @@ namespace WireMock.ResponseBuilders
/// The delay.
///
///
- /// The .
+ /// The .
///
public IResponseBuilder WithDelay(TimeSpan delay)
{
@@ -162,29 +182,36 @@ namespace WireMock.ResponseBuilders
///
public async Task ProvideResponse(RequestMessage requestMessage)
{
+ ResponseMessage responseMessage;
if (_useTransformer)
{
+ responseMessage = new ResponseMessage { StatusCode = ResponseMessage.StatusCode };
+
var template = new { request = requestMessage };
// Body
- var templateBody = Handlebars.Compile(_responseMessage.Body);
- _responseMessage.Body = templateBody(template);
+ var templateBody = Handlebars.Compile(ResponseMessage.Body);
+ responseMessage.Body = templateBody(template);
// Headers
var newHeaders = new Dictionary();
- foreach (var header in _responseMessage.Headers)
+ foreach (var header in ResponseMessage.Headers)
{
var templateHeaderKey = Handlebars.Compile(header.Key);
var templateHeaderValue = Handlebars.Compile(header.Value);
newHeaders.Add(templateHeaderKey(template), templateHeaderValue(template));
}
- _responseMessage.Headers = newHeaders;
+ responseMessage.Headers = newHeaders;
+ }
+ else
+ {
+ responseMessage = ResponseMessage;
}
await Task.Delay(_delay);
- return _responseMessage;
+ return responseMessage;
}
}
}
\ No newline at end of file
diff --git a/src/WireMock/RouteRegistrationCallback.cs b/src/WireMock/RouteRegistrationCallback.cs
index bc10b3a8..ad9d79a2 100644
--- a/src/WireMock/RouteRegistrationCallback.cs
+++ b/src/WireMock/RouteRegistrationCallback.cs
@@ -3,8 +3,8 @@
///
/// The registration callback.
///
- ///
+ ///
/// The route.
///
- public delegate void RegistrationCallback(Route route);
+ public delegate void RegistrationCallback(Mapping mapping);
}
\ No newline at end of file
diff --git a/src/WireMock/Server/FluentMockServer.Admin.cs b/src/WireMock/Server/FluentMockServer.Admin.cs
new file mode 100644
index 00000000..fd6e4615
--- /dev/null
+++ b/src/WireMock/Server/FluentMockServer.Admin.cs
@@ -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
+{
+ ///
+ /// The fluent mock server.
+ ///
+ 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();
+ foreach (var mapping in Mappings.Where(m => !(m.Provider is DynamicResponseProvider)))
+ {
+ var request = (Request) mapping.RequestMatcher;
+ var urlMatchers = request.GetRequestMessageMatchers();
+ var headerMatchers = request.GetRequestMessageMatchers();
+ var cookieMatchers = request.GetRequestMessageMatchers();
+ var paramsMatchers = request.GetRequestMessageMatchers();
+ var bodyMatcher = request.GetRequestMessageMatcher();
+ var verbMatcher = request.GetRequestMessageMatcher();
+
+ 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 Map([CanBeNull] IEnumerable 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 result)
+ {
+ return new ResponseMessage
+ {
+ Body = JsonConvert.SerializeObject(result, Formatting.Indented),
+ StatusCode = 200,
+ Headers = new Dictionary { { "Content-Type", "application/json" } }
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock/Server/FluentMockServer.cs b/src/WireMock/Server/FluentMockServer.cs
index bb4a379e..dc6172dc 100644
--- a/src/WireMock/Server/FluentMockServer.cs
+++ b/src/WireMock/Server/FluentMockServer.cs
@@ -16,7 +16,7 @@ namespace WireMock.Server
///
/// The fluent mock server.
///
- public class FluentMockServer
+ public partial class FluentMockServer
{
///
/// The _http server.
@@ -24,9 +24,9 @@ namespace WireMock.Server
private readonly TinyHttpServer _httpServer;
///
- /// The _routes.
+ /// The _mappings.
///
- private readonly IList _routes = new List();
+ private readonly IList _mappings = new List();
///
/// The _request logs.
@@ -75,13 +75,13 @@ namespace WireMock.Server
///
/// Gets the routes.
///
- public IEnumerable Routes
+ public IEnumerable Mappings
{
get
{
- lock (((ICollection)_routes).SyncRoot)
+ lock (((ICollection)_mappings).SyncRoot)
{
- return new ReadOnlyCollection(_routes);
+ return new ReadOnlyCollection(_mappings);
}
}
}
@@ -89,15 +89,9 @@ namespace WireMock.Server
///
/// Start this FluentMockServer.
///
- ///
- /// The port.
- ///
- ///
- /// The SSL support.
- ///
- ///
- /// The .
- ///
+ /// The port.
+ /// The SSL support.
+ /// The .
[PublicAPI]
public static FluentMockServer Start(int port = 0, bool ssl = false)
{
@@ -106,24 +100,37 @@ namespace WireMock.Server
if (port == 0)
port = Ports.FindFreeTcpPort();
- return new FluentMockServer(port, ssl);
+ return new FluentMockServer(false, port, ssl);
}
///
- /// Initializes a new instance of the class, and starts the server.
+ /// Start this FluentMockServer with the admin interface.
///
- ///
- /// The port.
- ///
- ///
- /// The SSL support.
- ///
- private FluentMockServer(int port, bool ssl)
+ /// The port.
+ /// The SSL support.
+ /// The .
+ [PublicAPI]
+ public static FluentMockServer StartWithAdminInterface(int port = 0, bool ssl = false)
+ {
+ 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";
- _httpServer = new TinyHttpServer(protocol + "://localhost:" + port + "/", HandleRequest);
+ _httpServer = new TinyHttpServer(protocol + "://localhost:" + port + "/", HandleRequestAsync);
Port = port;
_httpServer.Start();
+
+ if (startAdmin)
+ {
+ InitAdmin();
+ }
}
///
@@ -144,9 +151,9 @@ namespace WireMock.Server
_requestLogs.Clear();
}
- lock (((ICollection)_routes).SyncRoot)
+ lock (((ICollection)_mappings).SyncRoot)
{
- _routes.Clear();
+ _mappings.Clear();
}
}
@@ -184,28 +191,24 @@ namespace WireMock.Server
///
/// The given.
///
- ///
- /// The request matcher.
- ///
- ///
- /// The .
- ///
+ /// The request matcher.
+ /// The .
public IRespondWithAProvider Given(IRequestMatcher requestMatcher)
{
- return new RespondWithAProvider(RegisterRoute, requestMatcher);
+ return new RespondWithAProvider(RegisterMapping, requestMatcher);
}
///
- /// The register route.
+ /// The register mapping.
///
- ///
- /// The route.
+ ///
+ /// The mapping.
///
- 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
///
/// The handle request.
///
- ///
- /// The context.
- ///
- private async void HandleRequest(HttpListenerContext ctx)
+ /// The HttpListenerContext.
+ private async void HandleRequestAsync(HttpListenerContext ctx)
{
lock (_syncRoot)
{
@@ -241,7 +242,7 @@ namespace WireMock.Server
try
{
- var targetRoute = _routes.FirstOrDefault(route => route.IsRequestHandled(request));
+ var targetRoute = _mappings.FirstOrDefault(route => route.IsRequestHandled(request));
if (targetRoute == null)
{
ctx.Response.StatusCode = 404;
diff --git a/src/WireMock/Server/IRespondWithAProvider.cs b/src/WireMock/Server/IRespondWithAProvider.cs
index 2c575f72..51439006 100644
--- a/src/WireMock/Server/IRespondWithAProvider.cs
+++ b/src/WireMock/Server/IRespondWithAProvider.cs
@@ -11,6 +11,6 @@
///
/// The provider.
///
- void RespondWith(IProvideResponses provider);
+ void RespondWith(IResponseProvider provider);
}
}
\ No newline at end of file
diff --git a/src/WireMock/Server/RespondWithAProvider.cs b/src/WireMock/Server/RespondWithAProvider.cs
index 0ea517f2..2cb78aad 100644
--- a/src/WireMock/Server/RespondWithAProvider.cs
+++ b/src/WireMock/Server/RespondWithAProvider.cs
@@ -15,21 +15,17 @@ namespace WireMock.Server
///
/// The _request matcher.
///
- private readonly IRequestMatcher _requestSpec;
+ private readonly IRequestMatcher _requestMatcher;
///
/// Initializes a new instance of the class.
///
- ///
- /// The registration callback.
- ///
- ///
- /// The request matcher.
- ///
- public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestSpec)
+ /// The registration callback.
+ /// The request matcher.
+ public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestMatcher)
{
_registrationCallback = registrationCallback;
- _requestSpec = requestSpec;
+ _requestMatcher = requestMatcher;
}
///
@@ -38,9 +34,9 @@ namespace WireMock.Server
///
/// The provider.
///
- public void RespondWith(IProvideResponses provider)
+ public void RespondWith(IResponseProvider provider)
{
- _registrationCallback(new Route(_requestSpec, provider));
+ _registrationCallback(new Mapping(_requestMatcher, provider));
}
}
}
\ No newline at end of file
diff --git a/src/WireMock/Util/WireMockList.cs b/src/WireMock/Util/WireMockList.cs
index 4f84d8b1..73f4747a 100644
--- a/src/WireMock/Util/WireMockList.cs
+++ b/src/WireMock/Util/WireMockList.cs
@@ -17,6 +17,14 @@ namespace WireMock.Util
{
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The collection whose elements are copied to the new list.
+ public WireMockList(params T[] collection) : base(collection)
+ {
+ }
+
///
/// Initializes a new instance of the class.
///
diff --git a/src/WireMock/project.json b/src/WireMock/project.json
index 7c85d66a..2cc1256e 100644
--- a/src/WireMock/project.json
+++ b/src/WireMock/project.json
@@ -6,13 +6,14 @@
"packOptions": {
"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" ],
"repository": {
"type": "git",
"url": "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",
"releaseNotes": "First version"
},
diff --git a/test/WireMock.Net.Tests/FluentMockServerTests.cs b/test/WireMock.Net.Tests/FluentMockServerTests.cs
index c3b720f2..b27786d8 100644
--- a/test/WireMock.Net.Tests/FluentMockServerTests.cs
+++ b/test/WireMock.Net.Tests/FluentMockServerTests.cs
@@ -30,7 +30,7 @@ namespace WireMock.Net.Tests
_server.Given(Request.Create().WithUrl("/foo2").UsingGet())
.RespondWith(Response.Create().WithStatusCode(202).WithBody("2"));
- var routes = _server.Routes;
+ var routes = _server.Mappings;
Check.That(routes).HasSize(2);
Check.That(routes.First().RequestMatcher).IsNotNull();
diff --git a/test/WireMock.Net.Tests/RequestMessageTests.cs b/test/WireMock.Net.Tests/RequestMessageTests.cs
index 9d8e0547..2e74c704 100644
--- a/test/WireMock.Net.Tests/RequestMessageTests.cs
+++ b/test/WireMock.Net.Tests/RequestMessageTests.cs
@@ -12,12 +12,10 @@ namespace WireMock.Net.Tests
public void Should_handle_empty_query()
{
// given
- string bodyAsString = "whatever";
- byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
- var request = new RequestMessage(new Uri("http://localhost/foo"), "POST", body, bodyAsString);
+ var request = new RequestMessage(new Uri("http://localhost/foo"), "POST");
// then
- Check.That(request.GetParameter("foo")).IsEmpty();
+ Check.That(request.GetParameter("not_there")).IsNull();
}
[Test]
diff --git a/test/WireMock.Net.Tests/RequestTests.cs b/test/WireMock.Net.Tests/RequestTests.cs
index 79cc0d0f..fb1660c1 100644
--- a/test/WireMock.Net.Tests/RequestTests.cs
+++ b/test/WireMock.Net.Tests/RequestTests.cs
@@ -40,6 +40,19 @@ namespace WireMock.Net.Tests
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]
public void Should_specify_requests_matching_given_url_prefix()
{
@@ -394,7 +407,7 @@ namespace WireMock.Net.Tests
}
[Test]
- public void Should_specify_requests_matching_given_params()
+ public void Should_specify_requests_matching_given_param()
{
// given
var spec = Request.Create().WithPath("/foo").WithParam("bar", "1", "2");
@@ -409,7 +422,20 @@ namespace WireMock.Net.Tests
}
[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
var spec = Request.Create().WithPath("/foo").UsingAnyVerb().WithParam(p => p.ContainsKey("bar"));