mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-31 22:23:05 +02:00
Rename to WireMock.Net
This commit is contained in:
16
src/WireMock.Net/Admin/BodyModel.cs
Normal file
16
src/WireMock.Net/Admin/BodyModel.cs
Normal 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
src/WireMock.Net/Admin/CookieModel.cs
Normal file
26
src/WireMock.Net/Admin/CookieModel.cs
Normal 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
src/WireMock.Net/Admin/FuncModel.cs
Normal file
7
src/WireMock.Net/Admin/FuncModel.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
//namespace WireMock.Admin
|
||||
//{
|
||||
// public class FuncModel
|
||||
// {
|
||||
// public string Name { get; set; }
|
||||
// }
|
||||
//}
|
||||
26
src/WireMock.Net/Admin/HeaderModel.cs
Normal file
26
src/WireMock.Net/Admin/HeaderModel.cs
Normal 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
src/WireMock.Net/Admin/MappingModel.cs
Normal file
34
src/WireMock.Net/Admin/MappingModel.cs
Normal 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
src/WireMock.Net/Admin/MatcherModel.cs
Normal file
24
src/WireMock.Net/Admin/MatcherModel.cs
Normal 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
src/WireMock.Net/Admin/ParamModel.cs
Normal file
26
src/WireMock.Net/Admin/ParamModel.cs
Normal 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
src/WireMock.Net/Admin/RequestModel.cs
Normal file
55
src/WireMock.Net/Admin/RequestModel.cs
Normal 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
src/WireMock.Net/Admin/ResponseModel.cs
Normal file
34
src/WireMock.Net/Admin/ResponseModel.cs
Normal 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
src/WireMock.Net/Admin/UrlModel.cs
Normal file
18
src/WireMock.Net/Admin/UrlModel.cs
Normal 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
src/WireMock.Net/DynamicResponseProvider.cs
Normal file
24
src/WireMock.Net/DynamicResponseProvider.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
63
src/WireMock.Net/Extensions/DictionaryExtensions.cs
Normal file
63
src/WireMock.Net/Extensions/DictionaryExtensions.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
|
||||
namespace WireMock.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Dictionary Extensions
|
||||
/// </summary>
|
||||
public static class DictionaryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts IDictionary to an ExpandObject.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="dictionary">The dictionary.</param>
|
||||
/// <returns></returns>
|
||||
public static dynamic ToExpandoObject<T>(this IDictionary<string, T> dictionary)
|
||||
{
|
||||
dynamic expando = new ExpandoObject();
|
||||
var expandoDic = (IDictionary<string, object>)expando;
|
||||
|
||||
// go through the items in the dictionary and copy over the key value pairs)
|
||||
foreach (var kvp in dictionary)
|
||||
{
|
||||
// if the value can also be turned into an ExpandoObject, then do it!
|
||||
var value = kvp.Value as IDictionary<string, object>;
|
||||
if (value != null)
|
||||
{
|
||||
var expandoValue = value.ToExpandoObject();
|
||||
expandoDic.Add(kvp.Key, expandoValue);
|
||||
}
|
||||
else if (kvp.Value is ICollection)
|
||||
{
|
||||
// iterate through the collection and convert any strin-object dictionaries
|
||||
// along the way into expando objects
|
||||
var itemList = new List<object>();
|
||||
foreach (var item in (ICollection)kvp.Value)
|
||||
{
|
||||
var objects = item as IDictionary<string, object>;
|
||||
if (objects != null)
|
||||
{
|
||||
var expandoItem = objects.ToExpandoObject();
|
||||
itemList.Add(expandoItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemList.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
expandoDic.Add(kvp.Key, itemList);
|
||||
}
|
||||
else
|
||||
{
|
||||
expandoDic.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return expando;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/WireMock.Net/Http/Ports.cs
Normal file
34
src/WireMock.Net/Http/Ports.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace WireMock.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// The ports.
|
||||
/// </summary>
|
||||
public static class Ports
|
||||
{
|
||||
/// <summary>
|
||||
/// The find free TCP port.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="int"/>.
|
||||
/// </returns>
|
||||
/// <remarks>see http://stackoverflow.com/questions/138043/find-the-next-tcp-port-in-net.</remarks>
|
||||
public static int FindFreeTcpPort()
|
||||
{
|
||||
TcpListener tcpListener = null;
|
||||
try
|
||||
{
|
||||
tcpListener = new TcpListener(IPAddress.Loopback, 0);
|
||||
tcpListener.Start();
|
||||
|
||||
return ((IPEndPoint)tcpListener.LocalEndpoint).Port;
|
||||
}
|
||||
finally
|
||||
{
|
||||
tcpListener?.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
77
src/WireMock.Net/Http/TinyHttpServer.cs
Normal file
77
src/WireMock.Net/Http/TinyHttpServer.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WireMock.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// The tiny http server.
|
||||
/// </summary>
|
||||
public class TinyHttpServer
|
||||
{
|
||||
private readonly Action<HttpListenerContext> _httpHandler;
|
||||
|
||||
private readonly HttpListener _listener;
|
||||
|
||||
private CancellationTokenSource _cts;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this server is started.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this server is started; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsStarted { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TinyHttpServer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="urlPrefix">
|
||||
/// The url prefix.
|
||||
/// </param>
|
||||
/// <param name="httpHandler">
|
||||
/// The http handler.
|
||||
/// </param>
|
||||
public TinyHttpServer(string urlPrefix, Action<HttpListenerContext> httpHandler)
|
||||
{
|
||||
_httpHandler = httpHandler;
|
||||
|
||||
// Create a listener.
|
||||
_listener = new HttpListener();
|
||||
_listener.Prefixes.Add(urlPrefix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the server.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
_listener.Start();
|
||||
IsStarted = true;
|
||||
|
||||
_cts = new CancellationTokenSource();
|
||||
Task.Run(
|
||||
async () =>
|
||||
{
|
||||
using (_listener)
|
||||
{
|
||||
while (!_cts.Token.IsCancellationRequested)
|
||||
{
|
||||
HttpListenerContext context = await _listener.GetContextAsync();
|
||||
_httpHandler(context);
|
||||
}
|
||||
}
|
||||
},
|
||||
_cts.Token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the server.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
_cts.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/WireMock.Net/HttpListenerRequestMapper.cs
Normal file
57
src/WireMock.Net/HttpListenerRequestMapper.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace WireMock
|
||||
{
|
||||
/// <summary>
|
||||
/// The http listener request mapper.
|
||||
/// </summary>
|
||||
public class HttpListenerRequestMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// The map.
|
||||
/// </summary>
|
||||
/// <param name="listenerRequest">The listener request.</param>
|
||||
/// <returns>The <see cref="RequestMessage"/>.</returns>
|
||||
public RequestMessage Map(HttpListenerRequest listenerRequest)
|
||||
{
|
||||
Uri url = listenerRequest.Url;
|
||||
string verb = listenerRequest.HttpMethod;
|
||||
byte[] body = GetRequestBody(listenerRequest);
|
||||
string bodyAsString = body != null ? listenerRequest.ContentEncoding.GetString(body) : null;
|
||||
var listenerHeaders = listenerRequest.Headers;
|
||||
var headers = listenerHeaders.AllKeys.ToDictionary(k => k, k => listenerHeaders[k]);
|
||||
var cookies = new Dictionary<string, string>();
|
||||
foreach (Cookie cookie in listenerRequest.Cookies)
|
||||
cookies.Add(cookie.Name, cookie.Value);
|
||||
|
||||
return new RequestMessage(url, verb, body, bodyAsString, headers, cookies);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The get request body.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>The <see cref="string"/>.</returns>
|
||||
private byte[] GetRequestBody(HttpListenerRequest request)
|
||||
{
|
||||
if (!request.HasEntityBody)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var bodyStream = request.InputStream)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
bodyStream.CopyTo(memoryStream);
|
||||
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/WireMock.Net/HttpListenerResponseMapper.cs
Normal file
34
src/WireMock.Net/HttpListenerResponseMapper.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace WireMock
|
||||
{
|
||||
/// <summary>
|
||||
/// The http listener response mapper.
|
||||
/// </summary>
|
||||
public class HttpListenerResponseMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// The map.
|
||||
/// </summary>
|
||||
/// <param name="responseMessage">
|
||||
/// The response.
|
||||
/// </param>
|
||||
/// <param name="result">
|
||||
/// The result.
|
||||
/// </param>
|
||||
public void Map(ResponseMessage responseMessage, HttpListenerResponse result)
|
||||
{
|
||||
result.StatusCode = responseMessage.StatusCode;
|
||||
|
||||
responseMessage.Headers.ToList().ForEach(pair => result.AddHeader(pair.Key, pair.Value));
|
||||
|
||||
if (responseMessage.Body != null)
|
||||
{
|
||||
var content = Encoding.UTF8.GetBytes(responseMessage.Body);
|
||||
result.OutputStream.Write(content, 0, content.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/WireMock.Net/IResponseProvider.cs
Normal file
21
src/WireMock.Net/IResponseProvider.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WireMock
|
||||
{
|
||||
/// <summary>
|
||||
/// The Response Provider interface.
|
||||
/// </summary>
|
||||
public interface IResponseProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// The provide response.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">
|
||||
/// The request.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="Task"/>.
|
||||
/// </returns>
|
||||
Task<ResponseMessage> ProvideResponse(RequestMessage requestMessage);
|
||||
}
|
||||
}
|
||||
54
src/WireMock.Net/Mapping.cs
Normal file
54
src/WireMock.Net/Mapping.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock
|
||||
{
|
||||
/// <summary>
|
||||
/// The route.
|
||||
/// </summary>
|
||||
public class Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// The Request matcher.
|
||||
/// </summary>
|
||||
public IRequestMatcher RequestMatcher { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Provider.
|
||||
/// </summary>
|
||||
public IResponseProvider Provider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Mapping"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requestMatcher">The request matcher.</param>
|
||||
/// <param name="provider">The provider.</param>
|
||||
public Mapping(IRequestMatcher requestMatcher, IResponseProvider provider)
|
||||
{
|
||||
RequestMatcher = requestMatcher;
|
||||
Provider = provider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The response to.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The request message.</param>
|
||||
/// <returns>The <see cref="Task"/>.</returns>
|
||||
public async Task<ResponseMessage> ResponseTo(RequestMessage requestMessage)
|
||||
{
|
||||
return await Provider.ProvideResponse(requestMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the RequestMessage is handled.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The request message.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if RequestMessage is handled; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsRequestHandled(RequestMessage requestMessage)
|
||||
{
|
||||
return RequestMatcher.IsMatch(requestMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/WireMock.Net/Matchers/IMatcher.cs
Normal file
23
src/WireMock.Net/Matchers/IMatcher.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace WireMock.Matchers
|
||||
{
|
||||
/// <summary>
|
||||
/// IMatcher
|
||||
/// </summary>
|
||||
public interface IMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the specified input is match.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified input is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
bool IsMatch(string input);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pattern.
|
||||
/// </summary>
|
||||
/// <returns>Pattern</returns>
|
||||
string GetPattern();
|
||||
}
|
||||
}
|
||||
61
src/WireMock.Net/Matchers/JSONPathMatcher.cs
Normal file
61
src/WireMock.Net/Matchers/JSONPathMatcher.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers
|
||||
{
|
||||
/// <summary>
|
||||
/// JSONPathMatcher
|
||||
/// </summary>
|
||||
/// <seealso cref="WireMock.Matchers.IMatcher" />
|
||||
public class JsonPathMatcher : IMatcher
|
||||
{
|
||||
private readonly string _pattern;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
public JsonPathMatcher([NotNull] string pattern)
|
||||
{
|
||||
Check.NotNull(pattern, nameof(pattern));
|
||||
|
||||
_pattern = pattern;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified input is match.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified input is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(string input)
|
||||
{
|
||||
if (input == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
JObject o = JObject.Parse(input);
|
||||
JToken token = o.SelectToken(_pattern);
|
||||
|
||||
return token != null;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pattern.
|
||||
/// </summary>
|
||||
/// <returns>Pattern</returns>
|
||||
public string GetPattern()
|
||||
{
|
||||
return _pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/WireMock.Net/Matchers/RegexMatcher.cs
Normal file
60
src/WireMock.Net/Matchers/RegexMatcher.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers
|
||||
{
|
||||
/// <summary>
|
||||
/// Regular Expression Matcher
|
||||
/// </summary>
|
||||
/// <seealso cref="WireMock.Matchers.IMatcher" />
|
||||
public class RegexMatcher : IMatcher
|
||||
{
|
||||
private readonly string _pattern;
|
||||
private readonly Regex _expression;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegexMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
public RegexMatcher([NotNull, RegexPattern] string pattern)
|
||||
{
|
||||
Check.NotNull(pattern, nameof(pattern));
|
||||
|
||||
_pattern = pattern;
|
||||
_expression = new Regex(_pattern, RegexOptions.Compiled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified input is match.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified input is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(string input)
|
||||
{
|
||||
if (input == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
return _expression.IsMatch(input);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pattern.
|
||||
/// </summary>
|
||||
/// <returns>Pattern</returns>
|
||||
public string GetPattern()
|
||||
{
|
||||
return _pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/WireMock.Net/Matchers/Request/CompositeMatcherType.cs
Normal file
18
src/WireMock.Net/Matchers/Request/CompositeMatcherType.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// CompositeMatcherType
|
||||
/// </summary>
|
||||
public enum CompositeMatcherType
|
||||
{
|
||||
/// <summary>
|
||||
/// And
|
||||
/// </summary>
|
||||
And = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Or
|
||||
/// </summary>
|
||||
Or = 1
|
||||
}
|
||||
}
|
||||
19
src/WireMock.Net/Matchers/Request/IRequestMatcher.cs
Normal file
19
src/WireMock.Net/Matchers/Request/IRequestMatcher.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The RequestMatcher interface.
|
||||
/// </summary>
|
||||
public interface IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The RequestMessage.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
bool IsMatch([NotNull] RequestMessage requestMessage);
|
||||
}
|
||||
}
|
||||
124
src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
Normal file
124
src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The request body matcher.
|
||||
/// </summary>
|
||||
public class RequestMessageBodyMatcher : IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// The body.
|
||||
/// </summary>
|
||||
private readonly string _body;
|
||||
|
||||
/// <summary>
|
||||
/// The body as byte[].
|
||||
/// </summary>
|
||||
private readonly byte[] _bodyData;
|
||||
|
||||
/// <summary>
|
||||
/// The body function
|
||||
/// </summary>
|
||||
private readonly Func<string, bool> _bodyFunc;
|
||||
|
||||
/// <summary>
|
||||
/// The body data function
|
||||
/// </summary>
|
||||
private readonly Func<byte[], bool> _bodyDataFunc;
|
||||
|
||||
/// <summary>
|
||||
/// The matcher.
|
||||
/// </summary>
|
||||
public readonly IMatcher Matcher;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="body">
|
||||
/// The body Regex pattern.
|
||||
/// </param>
|
||||
public RequestMessageBodyMatcher([NotNull] string body)
|
||||
{
|
||||
Check.NotNull(body, nameof(body));
|
||||
_body = body;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="body">
|
||||
/// The body Regex pattern.
|
||||
/// </param>
|
||||
public RequestMessageBodyMatcher([NotNull] byte[] body)
|
||||
{
|
||||
Check.NotNull(body, nameof(body));
|
||||
_bodyData = body;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="func">
|
||||
/// The body func.
|
||||
/// </param>
|
||||
public RequestMessageBodyMatcher([NotNull] Func<string, bool> func)
|
||||
{
|
||||
Check.NotNull(func, nameof(func));
|
||||
_bodyFunc = func;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="func">
|
||||
/// The body func.
|
||||
/// </param>
|
||||
public RequestMessageBodyMatcher([NotNull] Func<byte[], bool> func)
|
||||
{
|
||||
Check.NotNull(func, nameof(func));
|
||||
_bodyDataFunc = func;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matcher">
|
||||
/// The body matcher.
|
||||
/// </param>
|
||||
public RequestMessageBodyMatcher([NotNull] IMatcher matcher)
|
||||
{
|
||||
Check.NotNull(matcher, nameof(matcher));
|
||||
Matcher = matcher;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The RequestMessage.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(RequestMessage requestMessage)
|
||||
{
|
||||
if (Matcher != null)
|
||||
return Matcher.IsMatch(requestMessage.Body);
|
||||
|
||||
if (_body != null)
|
||||
return requestMessage.Body == _body;
|
||||
|
||||
if (_bodyData != null)
|
||||
return requestMessage.BodyAsBytes == _bodyData;
|
||||
|
||||
if (_bodyFunc != null)
|
||||
return _bodyFunc(requestMessage.Body);
|
||||
|
||||
if (_bodyDataFunc != null)
|
||||
return _bodyDataFunc(requestMessage.BodyAsBytes);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The composite request matcher.
|
||||
/// </summary>
|
||||
public abstract class RequestMessageCompositeMatcher : IRequestMatcher
|
||||
{
|
||||
private readonly CompositeMatcherType _type;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the request matchers.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The request matchers.
|
||||
/// </value>
|
||||
private IEnumerable<IRequestMatcher> RequestMatchers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageCompositeMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requestMatchers">The request matchers.</param>
|
||||
/// <param name="type">The CompositeMatcherType type (Defaults to 'And')</param>
|
||||
protected RequestMessageCompositeMatcher([NotNull] IEnumerable<IRequestMatcher> requestMatchers, CompositeMatcherType type = CompositeMatcherType.And)
|
||||
{
|
||||
Check.NotNull(requestMatchers, nameof(requestMatchers));
|
||||
|
||||
_type = type;
|
||||
RequestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The RequestMessage.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public virtual bool IsMatch(RequestMessage requestMessage)
|
||||
{
|
||||
return _type == CompositeMatcherType.And ?
|
||||
RequestMatchers.All(matcher => matcher.IsMatch(requestMessage)) :
|
||||
RequestMatchers.Any(matcher => matcher.IsMatch(requestMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The request cookie matcher.
|
||||
/// </summary>
|
||||
public class RequestMessageCookieMatcher : IRequestMatcher
|
||||
{
|
||||
private readonly Func<IDictionary<string, string>, bool>[] _cookieFuncs;
|
||||
|
||||
/// <summary>
|
||||
/// The name
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the matchers.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The matchers.
|
||||
/// </value>
|
||||
public IMatcher[] Matchers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
/// <param name="ignoreCase">The ignoreCase.</param>
|
||||
public RequestMessageCookieMatcher([NotNull] string name, [NotNull] string pattern, bool ignoreCase = true)
|
||||
{
|
||||
Check.NotNull(name, nameof(name));
|
||||
Check.NotNull(pattern, nameof(pattern));
|
||||
|
||||
Name = name;
|
||||
Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageCookieMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The funcs.</param>
|
||||
public RequestMessageCookieMatcher([NotNull] params Func<IDictionary<string, string>, bool>[] funcs)
|
||||
{
|
||||
Check.NotNull(funcs, nameof(funcs));
|
||||
_cookieFuncs = funcs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The RequestMessage.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(RequestMessage requestMessage)
|
||||
{
|
||||
if (_cookieFuncs != null)
|
||||
return _cookieFuncs.Any(cf => cf(requestMessage.Cookies));
|
||||
|
||||
if (requestMessage.Cookies == null)
|
||||
return false;
|
||||
|
||||
string headerValue = requestMessage.Cookies[Name];
|
||||
return Matchers.Any(m => m.IsMatch(headerValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The request header matcher.
|
||||
/// </summary>
|
||||
public class RequestMessageHeaderMatcher : IRequestMatcher
|
||||
{
|
||||
private readonly Func<IDictionary<string, string>, bool>[] _headerFuncs;
|
||||
|
||||
/// <summary>
|
||||
/// The name
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the matchers.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The matchers.
|
||||
/// </value>
|
||||
public IMatcher[] Matchers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
/// <param name="ignoreCase">The ignoreCase.</param>
|
||||
public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string pattern, bool ignoreCase = true)
|
||||
{
|
||||
Check.NotNull(name, nameof(name));
|
||||
Check.NotNull(pattern, nameof(pattern));
|
||||
|
||||
Name = name;
|
||||
Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The funcs.</param>
|
||||
public RequestMessageHeaderMatcher([NotNull] params Func<IDictionary<string, string>, bool>[] funcs)
|
||||
{
|
||||
Check.NotNull(funcs, nameof(funcs));
|
||||
_headerFuncs = funcs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The RequestMessage.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(RequestMessage requestMessage)
|
||||
{
|
||||
if (_headerFuncs != null)
|
||||
return _headerFuncs.Any(hf => hf(requestMessage.Headers));
|
||||
|
||||
if (requestMessage.Headers == null)
|
||||
return false;
|
||||
|
||||
string headerValue = requestMessage.Headers[Name];
|
||||
return Matchers.Any(m => m.IsMatch(headerValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The request parameters matcher.
|
||||
/// </summary>
|
||||
public class RequestMessageParamMatcher : IRequestMatcher
|
||||
{
|
||||
private readonly Func<IDictionary<string, WireMockList<string>>, bool>[] _funcs;
|
||||
|
||||
/// <summary>
|
||||
/// The key
|
||||
/// </summary>
|
||||
public string Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The values
|
||||
/// </summary>
|
||||
public IEnumerable<string> Values { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// The key.
|
||||
/// </param>
|
||||
/// <param name="values">
|
||||
/// The values.
|
||||
/// </param>
|
||||
public RequestMessageParamMatcher([NotNull] string key, [NotNull] IEnumerable<string> values)
|
||||
{
|
||||
Check.NotNull(key, nameof(key));
|
||||
Check.NotNull(values, nameof(values));
|
||||
|
||||
Key = key;
|
||||
Values = values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The funcs.</param>
|
||||
public RequestMessageParamMatcher([NotNull] params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
|
||||
{
|
||||
Check.NotNull(funcs, nameof(funcs));
|
||||
_funcs = funcs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The RequestMessage.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(RequestMessage requestMessage)
|
||||
{
|
||||
if (_funcs != null)
|
||||
return _funcs.Any(f => f(requestMessage.Query));
|
||||
|
||||
var values = requestMessage.GetParameter(Key);
|
||||
return values?.Intersect(Values).Count() == Values.Count();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The request path matcher.
|
||||
/// </summary>
|
||||
public class RequestMessagePathMatcher : IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// The matcher.
|
||||
/// </summary>
|
||||
public IReadOnlyList<IMatcher> Matchers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The path functions
|
||||
/// </summary>
|
||||
private readonly Func<string, bool>[] _pathFuncs;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="paths">The paths.</param>
|
||||
public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).ToArray())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
public RequestMessagePathMatcher([NotNull] params IMatcher[] matchers)
|
||||
{
|
||||
Check.NotNull(matchers, nameof(matchers));
|
||||
Matchers = matchers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The path functions.</param>
|
||||
public RequestMessagePathMatcher([NotNull] params Func<string, bool>[] funcs)
|
||||
{
|
||||
Check.NotNull(funcs, nameof(funcs));
|
||||
_pathFuncs = funcs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The RequestMessage.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(RequestMessage requestMessage)
|
||||
{
|
||||
if (Matchers != null)
|
||||
return Matchers.Any(matcher => matcher.IsMatch(requestMessage.Path));
|
||||
|
||||
if (_pathFuncs != null)
|
||||
return _pathFuncs.Any(func => func(requestMessage.Path));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The request url matcher.
|
||||
/// </summary>
|
||||
public class RequestMessageUrlMatcher : IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// The matcher.
|
||||
/// </summary>
|
||||
public readonly IReadOnlyList<IMatcher> Matchers;
|
||||
|
||||
/// <summary>
|
||||
/// The url functions
|
||||
/// </summary>
|
||||
private readonly Func<string, bool>[] _urlFuncs;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="urls">The urls.</param>
|
||||
public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).ToArray())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
public RequestMessageUrlMatcher([NotNull] params IMatcher[] matchers)
|
||||
{
|
||||
Check.NotNull(matchers, nameof(matchers));
|
||||
Matchers = matchers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The url functions.</param>
|
||||
public RequestMessageUrlMatcher([NotNull] params Func<string, bool>[] funcs)
|
||||
{
|
||||
Check.NotNull(funcs, nameof(funcs));
|
||||
_urlFuncs = funcs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The RequestMessage.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(RequestMessage requestMessage)
|
||||
{
|
||||
if (Matchers != null)
|
||||
return Matchers.Any(matcher => matcher.IsMatch(requestMessage.Path));
|
||||
|
||||
if (_urlFuncs != null)
|
||||
return _urlFuncs.Any(func => func(requestMessage.Url));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers.Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The request verb matcher.
|
||||
/// </summary>
|
||||
internal class RequestMessageVerbMatcher : IRequestMatcher
|
||||
{
|
||||
/// <summary>
|
||||
/// The verbs
|
||||
/// </summary>
|
||||
public string[] Verbs { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessageVerbMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="verbs">
|
||||
/// The verb.
|
||||
/// </param>
|
||||
public RequestMessageVerbMatcher([NotNull] params string[] verbs)
|
||||
{
|
||||
Check.NotNull(verbs, nameof(verbs));
|
||||
Verbs = verbs.Select(v => v.ToLower()).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified RequestMessage is match.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">The RequestMessage.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified RequestMessage is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(RequestMessage requestMessage)
|
||||
{
|
||||
return Verbs.Contains(requestMessage.Verb);
|
||||
}
|
||||
}
|
||||
}
|
||||
111
src/WireMock.Net/Matchers/WildcardMatcher.cs
Normal file
111
src/WireMock.Net/Matchers/WildcardMatcher.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Matchers
|
||||
{
|
||||
/// <summary>
|
||||
/// WildcardMatcher
|
||||
/// </summary>
|
||||
/// <seealso cref="WireMock.Matchers.IMatcher" />
|
||||
public class WildcardMatcher : IMatcher
|
||||
{
|
||||
private readonly string _pattern;
|
||||
private readonly bool _ignoreCase;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegexMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
/// <param name="ignoreCase">IgnoreCase</param>
|
||||
public WildcardMatcher([NotNull] string pattern, bool ignoreCase = false)
|
||||
{
|
||||
Check.NotNull(pattern, nameof(pattern));
|
||||
|
||||
_pattern = pattern;
|
||||
_ignoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified input is match.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified input is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(string input)
|
||||
{
|
||||
return MatchWildcardString(_pattern, input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pattern.
|
||||
/// </summary>
|
||||
/// <returns>Pattern</returns>
|
||||
public string GetPattern()
|
||||
{
|
||||
return _pattern;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy/paste from http://www.codeproject.com/Tips/57304/Use-wildcard-characters-and-to-compare-strings
|
||||
/// </summary>
|
||||
private bool MatchWildcardString([NotNull] string pattern, string input)
|
||||
{
|
||||
if (input != null && _ignoreCase)
|
||||
input = input.ToLower();
|
||||
|
||||
if (_ignoreCase)
|
||||
pattern = pattern.ToLower();
|
||||
|
||||
if (string.CompareOrdinal(pattern, input) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return string.IsNullOrEmpty(pattern.Trim('*'));
|
||||
}
|
||||
|
||||
if (pattern.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pattern[0] == '?')
|
||||
{
|
||||
return MatchWildcardString(pattern.Substring(1), input.Substring(1));
|
||||
}
|
||||
|
||||
if (pattern[pattern.Length - 1] == '?')
|
||||
{
|
||||
return MatchWildcardString(pattern.Substring(0, pattern.Length - 1), input.Substring(0, input.Length - 1));
|
||||
}
|
||||
|
||||
if (pattern[0] == '*')
|
||||
{
|
||||
if (MatchWildcardString(pattern.Substring(1), input))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return MatchWildcardString(pattern, input.Substring(1));
|
||||
}
|
||||
|
||||
if (pattern[pattern.Length - 1] == '*')
|
||||
{
|
||||
if (MatchWildcardString(pattern.Substring(0, pattern.Length - 1), input))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return MatchWildcardString(pattern, input.Substring(0, input.Length - 1));
|
||||
}
|
||||
|
||||
if (pattern[0] == input[0])
|
||||
{
|
||||
return MatchWildcardString(pattern.Substring(1), input.Substring(1));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
62
src/WireMock.Net/Matchers/XPathMatcher.cs
Normal file
62
src/WireMock.Net/Matchers/XPathMatcher.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
using Wmhelp.XPath2;
|
||||
|
||||
namespace WireMock.Matchers
|
||||
{
|
||||
/// <summary>
|
||||
/// XPath2Matcher
|
||||
/// </summary>
|
||||
/// <seealso cref="WireMock.Matchers.IMatcher" />
|
||||
public class XPathMatcher : IMatcher
|
||||
{
|
||||
private readonly string _pattern;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="XPathMatcher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
public XPathMatcher([NotNull] string pattern)
|
||||
{
|
||||
Check.NotNull(pattern, nameof(pattern));
|
||||
|
||||
_pattern = pattern;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified input is match.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified input is match; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMatch(string input)
|
||||
{
|
||||
if (input == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
var nav = new XmlDocument { InnerXml = input }.CreateNavigator();
|
||||
object result = nav.XPath2Evaluate($"boolean({_pattern})");
|
||||
|
||||
return true.Equals(result);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pattern.
|
||||
/// </summary>
|
||||
/// <returns>Pattern</returns>
|
||||
public string GetPattern()
|
||||
{
|
||||
return _pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
68
src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs
Normal file
68
src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The BodyRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IBodyRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The with body.
|
||||
/// </summary>
|
||||
/// <param name="matcher">
|
||||
/// The matcher.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
IRequestMatcher WithBody([NotNull] IMatcher matcher);
|
||||
|
||||
/// <summary>
|
||||
/// The with body.
|
||||
/// </summary>
|
||||
/// <param name="body">
|
||||
/// The body.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
IRequestMatcher WithBody(string body);
|
||||
|
||||
/// <summary>
|
||||
/// The with body byte[].
|
||||
/// </summary>
|
||||
/// <param name="body">
|
||||
/// The body as byte[].
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
IRequestMatcher WithBody(byte[] body);
|
||||
|
||||
/// <summary>
|
||||
/// The with body string func.
|
||||
/// </summary>
|
||||
/// <param name="body">
|
||||
/// The body string function.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
IRequestMatcher WithBody(Func<string, bool> body);
|
||||
|
||||
/// <summary>
|
||||
/// The with body byte[] func.
|
||||
/// </summary>
|
||||
/// <param name="body">
|
||||
/// The body byte[] function.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
IRequestMatcher WithBody(Func<byte[], bool> body);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.RequestBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The HeadersAndCookieRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IHeadersAndCookiesRequestBuilder : IBodyRequestBuilder, IRequestMatcher, IParamsRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The with header.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
/// <param name="ignoreCase">ignore Case</param>
|
||||
/// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns>
|
||||
IHeadersAndCookiesRequestBuilder WithHeader(string name, string pattern, bool ignoreCase = true);
|
||||
|
||||
/// <summary>
|
||||
/// The with header.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The headers funcs.</param>
|
||||
/// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns>
|
||||
IHeadersAndCookiesRequestBuilder WithHeader([NotNull] params Func<IDictionary<string, string>, bool>[] funcs);
|
||||
|
||||
/// <summary>
|
||||
/// The with header.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
/// <param name="ignoreCase">ignore Case</param>
|
||||
/// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns>
|
||||
IHeadersAndCookiesRequestBuilder WithCookie(string name, string pattern, bool ignoreCase = true);
|
||||
|
||||
/// <summary>
|
||||
/// The with header.
|
||||
/// </summary>
|
||||
/// <param name="cookieFuncs">The funcs.</param>
|
||||
/// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns>
|
||||
IHeadersAndCookiesRequestBuilder WithCookie([NotNull] params Func<IDictionary<string, string>, bool>[] cookieFuncs);
|
||||
}
|
||||
}
|
||||
35
src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs
Normal file
35
src/WireMock.Net/RequestBuilders/IParamsRequestBuilder.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.RequestBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The ParametersRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IParamsRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The with parameters.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// The key.
|
||||
/// </param>
|
||||
/// <param name="values">
|
||||
/// The values.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
IRequestMatcher WithParam([NotNull] string key, params string[] values);
|
||||
|
||||
/// <summary>
|
||||
/// The with parameters.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The funcs.</param>
|
||||
/// <returns>The <see cref="IRequestMatcher"/>.</returns>
|
||||
IRequestMatcher WithParam([NotNull] params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs);
|
||||
}
|
||||
}
|
||||
9
src/WireMock.Net/RequestBuilders/IRequestBuilder.cs
Normal file
9
src/WireMock.Net/RequestBuilders/IRequestBuilder.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace WireMock.RequestBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// IRequestBuilder
|
||||
/// </summary>
|
||||
public interface IRequestBuilder : IUrlAndPathRequestBuilder
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Matchers;
|
||||
|
||||
namespace WireMock.RequestBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// IUrlAndPathRequestBuilder
|
||||
/// </summary>
|
||||
public interface IUrlAndPathRequestBuilder : IVerbRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The with url.
|
||||
/// </summary>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
IUrlAndPathRequestBuilder WithUrl([NotNull] params IMatcher[] matchers);
|
||||
|
||||
/// <summary>
|
||||
/// The with url.
|
||||
/// </summary>
|
||||
/// <param name="urls">The urls.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
IUrlAndPathRequestBuilder WithUrl([NotNull] params string[] urls);
|
||||
|
||||
/// <summary>
|
||||
/// The with url.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The url funcs.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
IUrlAndPathRequestBuilder WithUrl([NotNull] params Func<string, bool>[] funcs);
|
||||
|
||||
/// <summary>
|
||||
/// The with path.
|
||||
/// </summary>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
IUrlAndPathRequestBuilder WithPath([NotNull] params IMatcher[] matchers);
|
||||
|
||||
/// <summary>
|
||||
/// The with path.
|
||||
/// </summary>
|
||||
/// <param name="paths">The paths.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
IUrlAndPathRequestBuilder WithPath([NotNull] params string[] paths);
|
||||
|
||||
/// <summary>
|
||||
/// The with path.
|
||||
/// </summary>
|
||||
/// <param name="func">The path func.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
IUrlAndPathRequestBuilder WithPath([NotNull] params Func<string, bool>[] func);
|
||||
}
|
||||
}
|
||||
65
src/WireMock.Net/RequestBuilders/IVerbRequestBuilder.cs
Normal file
65
src/WireMock.Net/RequestBuilders/IVerbRequestBuilder.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace WireMock.RequestBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The VerbRequestBuilder interface.
|
||||
/// </summary>
|
||||
public interface IVerbRequestBuilder : IHeadersAndCookiesRequestBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The using get.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
IHeadersAndCookiesRequestBuilder UsingGet();
|
||||
|
||||
/// <summary>
|
||||
/// The using post.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
IHeadersAndCookiesRequestBuilder UsingPost();
|
||||
|
||||
/// <summary>
|
||||
/// The using delete.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
IHeadersAndCookiesRequestBuilder UsingDelete();
|
||||
|
||||
/// <summary>
|
||||
/// The using put.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
IHeadersAndCookiesRequestBuilder UsingPut();
|
||||
|
||||
/// <summary>
|
||||
/// The using head.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
IHeadersAndCookiesRequestBuilder UsingHead();
|
||||
|
||||
/// <summary>
|
||||
/// The using any verb.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
IHeadersAndCookiesRequestBuilder UsingAnyVerb();
|
||||
|
||||
/// <summary>
|
||||
/// The using verb.
|
||||
/// </summary>
|
||||
/// <param name="verbs">The verb.</param>
|
||||
/// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns>
|
||||
IHeadersAndCookiesRequestBuilder UsingVerb([NotNull] params string[] verbs);
|
||||
}
|
||||
}
|
||||
360
src/WireMock.Net/RequestBuilders/Request.cs
Normal file
360
src/WireMock.Net/RequestBuilders/Request.cs
Normal file
@@ -0,0 +1,360 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.RequestBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The requests.
|
||||
/// </summary>
|
||||
public class Request : RequestMessageCompositeMatcher, IRequestBuilder
|
||||
{
|
||||
private readonly IList<IRequestMatcher> _requestMatchers;
|
||||
|
||||
/// <summary>
|
||||
/// Creates this instance.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||
public static IRequestBuilder Create()
|
||||
{
|
||||
return new Request(new List<IRequestMatcher>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Request"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requestMatchers">The request matchers.</param>
|
||||
private Request(IList<IRequestMatcher> requestMatchers) : base(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>
|
||||
/// The with url.
|
||||
/// </summary>
|
||||
/// <param name="matchers">The matchers.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
public IUrlAndPathRequestBuilder WithUrl(params IMatcher[] matchers)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageUrlMatcher(matchers));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with url.
|
||||
/// </summary>
|
||||
/// <param name="urls">The urls.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
public IUrlAndPathRequestBuilder WithUrl(params string[] urls)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageUrlMatcher(urls));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with url.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The url func.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
public IUrlAndPathRequestBuilder WithUrl(params Func<string, bool>[] funcs)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageUrlMatcher(funcs));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with url.
|
||||
/// </summary>
|
||||
/// <param name="matcher">The matcher.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
public IUrlAndPathRequestBuilder WithPath(params IMatcher[] matcher)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessagePathMatcher(matcher));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with path.
|
||||
/// </summary>
|
||||
/// <param name="paths">The path.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
public IUrlAndPathRequestBuilder WithPath(params string[] paths)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessagePathMatcher(paths));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with path.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The path func.</param>
|
||||
/// <returns>The <see cref="IUrlAndPathRequestBuilder"/>.</returns>
|
||||
public IUrlAndPathRequestBuilder WithPath(params Func<string, bool>[] funcs)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessagePathMatcher(funcs));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The using get.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
public IHeadersAndCookiesRequestBuilder UsingGet()
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageVerbMatcher("get"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The using post.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
public IHeadersAndCookiesRequestBuilder UsingPost()
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageVerbMatcher("post"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The using put.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
public IHeadersAndCookiesRequestBuilder UsingPut()
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageVerbMatcher("put"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The using delete.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
public IHeadersAndCookiesRequestBuilder UsingDelete()
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageVerbMatcher("delete"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The using head.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
public IHeadersAndCookiesRequestBuilder UsingHead()
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageVerbMatcher("head"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The using any verb.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IHeadersAndCookiesRequestBuilder"/>.
|
||||
/// </returns>
|
||||
public IHeadersAndCookiesRequestBuilder UsingAnyVerb()
|
||||
{
|
||||
var matchers = _requestMatchers.Where(m => m is RequestMessageVerbMatcher).ToList();
|
||||
foreach (var matcher in matchers)
|
||||
{
|
||||
_requestMatchers.Remove(matcher);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The using verb.
|
||||
/// </summary>
|
||||
/// <param name="verbs">The verbs.</param>
|
||||
/// <returns>The <see cref="IHeadersAndCookiesRequestBuilder"/>.</returns>
|
||||
public IHeadersAndCookiesRequestBuilder UsingVerb(params string[] verbs)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageVerbMatcher(verbs));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with body.
|
||||
/// </summary>
|
||||
/// <param name="body">
|
||||
/// The body.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
public IRequestMatcher WithBody(string body)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageBodyMatcher(body));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with body byte[].
|
||||
/// </summary>
|
||||
/// <param name="body">
|
||||
/// The body as byte[].
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
public IRequestMatcher WithBody(byte[] body)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageBodyMatcher(body));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with body.
|
||||
/// </summary>
|
||||
/// <param name="func">
|
||||
/// The body function.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
public IRequestMatcher WithBody(Func<string, bool> func)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with body.
|
||||
/// </summary>
|
||||
/// <param name="func">
|
||||
/// The body function.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
public IRequestMatcher WithBody(Func<byte[], bool> func)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with body.
|
||||
/// </summary>
|
||||
/// <param name="matcher">The matcher.</param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher" />.
|
||||
/// </returns>
|
||||
public IRequestMatcher WithBody(IMatcher matcher)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageBodyMatcher(matcher));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with parameters.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// The key.
|
||||
/// </param>
|
||||
/// <param name="values">
|
||||
/// The values.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IRequestMatcher"/>.
|
||||
/// </returns>
|
||||
public IRequestMatcher WithParam(string key, params string[] values)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageParamMatcher(key, values.ToList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with parameters.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The funcs.</param>
|
||||
/// <returns>The <see cref="IRequestMatcher"/>.</returns>
|
||||
public IRequestMatcher WithParam(params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageParamMatcher(funcs));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// With header.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
/// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
|
||||
/// <returns></returns>
|
||||
public IHeadersAndCookiesRequestBuilder WithHeader(string name, string pattern, bool ignoreCase = true)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageHeaderMatcher(name, pattern, ignoreCase));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// With header.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The funcs.</param>
|
||||
/// <returns></returns>
|
||||
public IHeadersAndCookiesRequestBuilder WithHeader(params Func<IDictionary<string, string>, bool>[] funcs)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageHeaderMatcher(funcs));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// With cookie.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="pattern">The pattern.</param>
|
||||
/// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
|
||||
/// <returns></returns>
|
||||
public IHeadersAndCookiesRequestBuilder WithCookie(string name, string pattern, bool ignoreCase = true)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageCookieMatcher(name, pattern, ignoreCase));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// With header.
|
||||
/// </summary>
|
||||
/// <param name="funcs">The funcs.</param>
|
||||
/// <returns></returns>
|
||||
public IHeadersAndCookiesRequestBuilder WithCookie(params Func<IDictionary<string, string>, bool>[] funcs)
|
||||
{
|
||||
_requestMatchers.Add(new RequestMessageCookieMatcher(funcs));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
114
src/WireMock.Net/RequestMessage.cs
Normal file
114
src/WireMock.Net/RequestMessage.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock
|
||||
{
|
||||
/// <summary>
|
||||
/// The request.
|
||||
/// </summary>
|
||||
public class RequestMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the url.
|
||||
/// </summary>
|
||||
public string Url { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path.
|
||||
/// </summary>
|
||||
public string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the verb.
|
||||
/// </summary>
|
||||
public string Verb { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the headers.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> Headers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cookies.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> Cookies { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the query.
|
||||
/// </summary>
|
||||
public IDictionary<string, WireMockList<string>> Query { get; } = new Dictionary<string, WireMockList<string>>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bodyAsBytes.
|
||||
/// </summary>
|
||||
public byte[] BodyAsBytes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the body.
|
||||
/// </summary>
|
||||
public string Body { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="url">The original url.</param>
|
||||
/// <param name="verb">The verb.</param>
|
||||
/// <param name="bodyAsBytes">The bodyAsBytes byte[].</param>
|
||||
/// <param name="body">The body string.</param>
|
||||
/// <param name="headers">The headers.</param>
|
||||
/// <param name="cookies">The cookies.</param>
|
||||
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(verb, nameof(verb));
|
||||
|
||||
Url = url.ToString();
|
||||
Path = url.AbsolutePath;
|
||||
Verb = verb.ToLower();
|
||||
BodyAsBytes = bodyAsBytes;
|
||||
Body = body;
|
||||
Headers = headers;
|
||||
Cookies = cookies;
|
||||
|
||||
string query = url.Query;
|
||||
if (!string.IsNullOrEmpty(query))
|
||||
{
|
||||
if (query.StartsWith("?"))
|
||||
{
|
||||
query = query.Substring(1);
|
||||
}
|
||||
|
||||
Query = query.Split('&').Aggregate(
|
||||
new Dictionary<string, WireMockList<string>>(),
|
||||
(dict, term) =>
|
||||
{
|
||||
var parts = term.Split('=');
|
||||
var key = parts[0];
|
||||
if (!dict.ContainsKey(key))
|
||||
{
|
||||
dict.Add(key, new WireMockList<string>());
|
||||
}
|
||||
|
||||
if (parts.Length == 2)
|
||||
dict[key].Add(parts[1]);
|
||||
|
||||
return dict;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The get a query parameter.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns>The query parameter.</returns>
|
||||
public List<string> GetParameter(string key)
|
||||
{
|
||||
return Query.ContainsKey(key) ? Query[key] : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs
Normal file
26
src/WireMock.Net/ResponseBuilders/IBodyResponseBuilder.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The BodyResponseBuilder interface.
|
||||
/// </summary>
|
||||
public interface IBodyResponseBuilder : ITransformResponseBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The with body.
|
||||
/// </summary>
|
||||
/// <param name="body">The body.</param>
|
||||
/// <returns>A <see cref="ITransformResponseBuilder"/>.</returns>
|
||||
ITransformResponseBuilder WithBody([NotNull] string body);
|
||||
|
||||
/// <summary>
|
||||
/// The with body as base64.
|
||||
/// </summary>
|
||||
/// <param name="bodyAsbase64">The body asbase64.</param>
|
||||
/// <param name="encoding">The Encoding.</param>
|
||||
/// <returns>A <see cref="ITransformResponseBuilder"/>.</returns>
|
||||
ITransformResponseBuilder WithBodyAsBase64([NotNull] string bodyAsbase64, [CanBeNull] Encoding encoding = null);
|
||||
}
|
||||
}
|
||||
17
src/WireMock.Net/ResponseBuilders/IDelayResponseBuilder.cs
Normal file
17
src/WireMock.Net/ResponseBuilders/IDelayResponseBuilder.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The DelayResponseBuilder interface.
|
||||
/// </summary>
|
||||
public interface IDelayResponseBuilder : IResponseProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// The after delay.
|
||||
/// </summary>
|
||||
/// <param name="delay">The delay.</param>
|
||||
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
|
||||
IResponseBuilder WithDelay(TimeSpan delay);
|
||||
}
|
||||
}
|
||||
18
src/WireMock.Net/ResponseBuilders/IHeadersResponseBuilder.cs
Normal file
18
src/WireMock.Net/ResponseBuilders/IHeadersResponseBuilder.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The HeadersResponseBuilder interface.
|
||||
/// </summary>
|
||||
public interface IHeadersResponseBuilder : IBodyResponseBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The with header.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The <see cref="IHeadersResponseBuilder"/>.</returns>
|
||||
IHeadersResponseBuilder WithHeader([NotNull] string name, string value);
|
||||
}
|
||||
}
|
||||
9
src/WireMock.Net/ResponseBuilders/IResponseBuilder.cs
Normal file
9
src/WireMock.Net/ResponseBuilders/IResponseBuilder.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The ResponseBuilder interface.
|
||||
/// </summary>
|
||||
public interface IResponseBuilder : IStatusCodeResponseBuilder
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Net;
|
||||
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The StatusCodeResponseBuilder interface.
|
||||
/// </summary>
|
||||
public interface IStatusCodeResponseBuilder : IHeadersResponseBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The with status code.
|
||||
/// </summary>
|
||||
/// <param name="code">
|
||||
/// The code.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="IHeadersResponseBuilder"/>.</returns>
|
||||
IHeadersResponseBuilder WithStatusCode(int code);
|
||||
|
||||
/// <summary>
|
||||
/// The with status code.
|
||||
/// </summary>
|
||||
/// <param name="code">
|
||||
/// The code.
|
||||
/// </param>
|
||||
/// <returns>The <see cref="IHeadersResponseBuilder"/>.</returns>
|
||||
IHeadersResponseBuilder WithStatusCode(HttpStatusCode code);
|
||||
|
||||
/// <summary>
|
||||
/// The with Success status code (200).
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
|
||||
IHeadersResponseBuilder WithSuccess();
|
||||
|
||||
/// <summary>
|
||||
/// The with NotFound status code (404).
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
|
||||
IHeadersResponseBuilder WithNotFound();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The BodyResponseBuilder interface.
|
||||
/// </summary>
|
||||
public interface ITransformResponseBuilder : IDelayResponseBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// The with transformer.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IDelayResponseBuilder"/>.
|
||||
/// </returns>
|
||||
IDelayResponseBuilder WithTransformer();
|
||||
}
|
||||
}
|
||||
217
src/WireMock.Net/ResponseBuilders/Response.cs
Normal file
217
src/WireMock.Net/ResponseBuilders/Response.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using HandlebarsDotNet;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.ResponseBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// The Response.
|
||||
/// </summary>
|
||||
public class Response : IResponseBuilder
|
||||
{
|
||||
private TimeSpan _delay = TimeSpan.Zero;
|
||||
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>
|
||||
/// Creates this instance.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
|
||||
[PublicAPI]
|
||||
public static IResponseBuilder Create([NotNull] Func<ResponseMessage> func)
|
||||
{
|
||||
Check.NotNull(func, nameof(func));
|
||||
|
||||
return new Response(func());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Response"/> class.
|
||||
/// </summary>
|
||||
/// <param name="responseMessage">
|
||||
/// The response.
|
||||
/// </param>
|
||||
private Response(ResponseMessage responseMessage)
|
||||
{
|
||||
ResponseMessage = responseMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with status code.
|
||||
/// </summary>
|
||||
/// <param name="code">The code.</param>
|
||||
/// <returns>A <see cref="IHeadersResponseBuilder"/>.</returns>\
|
||||
[PublicAPI]
|
||||
public IHeadersResponseBuilder WithStatusCode(int code)
|
||||
{
|
||||
ResponseMessage.StatusCode = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with status code.
|
||||
/// </summary>
|
||||
/// <param name="code">The code.</param>
|
||||
/// <returns>A <see cref="IHeadersResponseBuilder"/>.</returns>
|
||||
[PublicAPI]
|
||||
public IHeadersResponseBuilder WithStatusCode(HttpStatusCode code)
|
||||
{
|
||||
return WithStatusCode((int)code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with Success status code (200).
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public IHeadersResponseBuilder WithSuccess()
|
||||
{
|
||||
return WithStatusCode((int)HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with NotFound status code (404).
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
|
||||
[PublicAPI]
|
||||
public IHeadersResponseBuilder WithNotFound()
|
||||
{
|
||||
return WithStatusCode((int)HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with header.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The <see cref="IHeadersResponseBuilder"/>.</returns>
|
||||
public IHeadersResponseBuilder WithHeader(string name, string value)
|
||||
{
|
||||
Check.NotNull(name, nameof(name));
|
||||
|
||||
ResponseMessage.AddHeader(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with body.
|
||||
/// </summary>
|
||||
/// <param name="body">The body.</param>
|
||||
/// <returns>A <see cref="ITransformResponseBuilder"/>.</returns>
|
||||
public ITransformResponseBuilder WithBody(string body)
|
||||
{
|
||||
Check.NotNull(body, nameof(body));
|
||||
|
||||
ResponseMessage.Body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with body as base64.
|
||||
/// </summary>
|
||||
/// <param name="bodyAsbase64">The body asbase64.</param>
|
||||
/// <param name="encoding">The Encoding.</param>
|
||||
/// <returns>A <see cref="ITransformResponseBuilder"/>.</returns>
|
||||
public ITransformResponseBuilder WithBodyAsBase64(string bodyAsbase64, Encoding encoding = null)
|
||||
{
|
||||
Check.NotNull(bodyAsbase64, nameof(bodyAsbase64));
|
||||
|
||||
ResponseMessage.Body = (encoding ?? Encoding.UTF8).GetString(Convert.FromBase64String(bodyAsbase64));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The with transformer.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IResponseBuilder"/>.
|
||||
/// </returns>
|
||||
public IDelayResponseBuilder WithTransformer()
|
||||
{
|
||||
_useTransformer = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The after delay.
|
||||
/// </summary>
|
||||
/// <param name="delay">
|
||||
/// The delay.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IResponseProvider"/>.
|
||||
/// </returns>
|
||||
public IResponseBuilder WithDelay(TimeSpan delay)
|
||||
{
|
||||
_delay = delay;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The provide response.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">
|
||||
/// The request.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="Task"/>.
|
||||
/// </returns>
|
||||
public async Task<ResponseMessage> 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);
|
||||
|
||||
// Headers
|
||||
var newHeaders = new Dictionary<string, string>();
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
responseMessage = ResponseMessage;
|
||||
}
|
||||
|
||||
await Task.Delay(_delay);
|
||||
|
||||
return responseMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/WireMock.Net/ResponseMessage.cs
Normal file
39
src/WireMock.Net/ResponseMessage.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
namespace WireMock
|
||||
{
|
||||
/// <summary>
|
||||
/// The response.
|
||||
/// </summary>
|
||||
public class ResponseMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the headers.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> Headers { get; set; } = new ConcurrentDictionary<string, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status code.
|
||||
/// </summary>
|
||||
public int StatusCode { get; set; } = 200;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the body.
|
||||
/// </summary>
|
||||
public string Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The add header.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// The name.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The value.
|
||||
/// </param>
|
||||
public void AddHeader(string name, string value)
|
||||
{
|
||||
Headers.Add(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/WireMock.Net/RouteRegistrationCallback.cs
Normal file
10
src/WireMock.Net/RouteRegistrationCallback.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace WireMock
|
||||
{
|
||||
/// <summary>
|
||||
/// The registration callback.
|
||||
/// </summary>
|
||||
/// <param name="mapping">
|
||||
/// The route.
|
||||
/// </param>
|
||||
public delegate void RegistrationCallback(Mapping mapping);
|
||||
}
|
||||
110
src/WireMock.Net/Server/FluentMockServer.Admin.cs
Normal file
110
src/WireMock.Net/Server/FluentMockServer.Admin.cs
Normal file
@@ -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" } }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
272
src/WireMock.Net/Server/FluentMockServer.cs
Normal file
272
src/WireMock.Net/Server/FluentMockServer.cs
Normal file
@@ -0,0 +1,272 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Http;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// The fluent mock server.
|
||||
/// </summary>
|
||||
public partial class FluentMockServer
|
||||
{
|
||||
/// <summary>
|
||||
/// The _http server.
|
||||
/// </summary>
|
||||
private readonly TinyHttpServer _httpServer;
|
||||
|
||||
/// <summary>
|
||||
/// The _mappings.
|
||||
/// </summary>
|
||||
private readonly IList<Mapping> _mappings = new List<Mapping>();
|
||||
|
||||
/// <summary>
|
||||
/// The _request logs.
|
||||
/// </summary>
|
||||
private readonly IList<RequestMessage> _requestLogs = new List<RequestMessage>();
|
||||
|
||||
/// <summary>
|
||||
/// The _request mapper.
|
||||
/// </summary>
|
||||
private readonly HttpListenerRequestMapper _requestMapper = new HttpListenerRequestMapper();
|
||||
|
||||
/// <summary>
|
||||
/// The _response mapper.
|
||||
/// </summary>
|
||||
private readonly HttpListenerResponseMapper _responseMapper = new HttpListenerResponseMapper();
|
||||
|
||||
/// <summary>
|
||||
/// The _sync root.
|
||||
/// </summary>
|
||||
private readonly object _syncRoot = new object();
|
||||
|
||||
/// <summary>
|
||||
/// The _request processing delay.
|
||||
/// </summary>
|
||||
private TimeSpan _requestProcessingDelay = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the port.
|
||||
/// </summary>
|
||||
public int Port { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the request logs.
|
||||
/// </summary>
|
||||
public IEnumerable<RequestMessage> RequestLogs
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (((ICollection)_requestLogs).SyncRoot)
|
||||
{
|
||||
return new ReadOnlyCollection<RequestMessage>(_requestLogs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the routes.
|
||||
/// </summary>
|
||||
public IEnumerable<Mapping> Mappings
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (((ICollection)_mappings).SyncRoot)
|
||||
{
|
||||
return new ReadOnlyCollection<Mapping>(_mappings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start this FluentMockServer.
|
||||
/// </summary>
|
||||
/// <param name="port">The port.</param>
|
||||
/// <param name="ssl">The SSL support.</param>
|
||||
/// <returns>The <see cref="FluentMockServer"/>.</returns>
|
||||
[PublicAPI]
|
||||
public static FluentMockServer Start(int port = 0, bool ssl = false)
|
||||
{
|
||||
Check.Condition(port, p => p >= 0, nameof(port));
|
||||
|
||||
if (port == 0)
|
||||
port = Ports.FindFreeTcpPort();
|
||||
|
||||
return new FluentMockServer(false, port, ssl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start this FluentMockServer with the admin interface.
|
||||
/// </summary>
|
||||
/// <param name="port">The port.</param>
|
||||
/// <param name="ssl">The SSL support.</param>
|
||||
/// <returns>The <see cref="FluentMockServer"/>.</returns>
|
||||
[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 + "/", HandleRequestAsync);
|
||||
Port = port;
|
||||
_httpServer.Start();
|
||||
|
||||
if (startAdmin)
|
||||
{
|
||||
InitAdmin();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop this server.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
_httpServer.Stop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The reset.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
lock (((ICollection)_requestLogs).SyncRoot)
|
||||
{
|
||||
_requestLogs.Clear();
|
||||
}
|
||||
|
||||
lock (((ICollection)_mappings).SyncRoot)
|
||||
{
|
||||
_mappings.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The search logs for.
|
||||
/// </summary>
|
||||
/// <param name="spec">
|
||||
/// The matcher.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IEnumerable"/>.
|
||||
/// </returns>
|
||||
public IEnumerable<RequestMessage> SearchLogsFor(IRequestMatcher spec)
|
||||
{
|
||||
lock (((ICollection)_requestLogs).SyncRoot)
|
||||
{
|
||||
return _requestLogs.Where(spec.IsMatch);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The add request processing delay.
|
||||
/// </summary>
|
||||
/// <param name="delay">
|
||||
/// The delay.
|
||||
/// </param>
|
||||
public void AddRequestProcessingDelay(TimeSpan delay)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_requestProcessingDelay = delay;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The given.
|
||||
/// </summary>
|
||||
/// <param name="requestMatcher">The request matcher.</param>
|
||||
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
|
||||
public IRespondWithAProvider Given(IRequestMatcher requestMatcher)
|
||||
{
|
||||
return new RespondWithAProvider(RegisterMapping, requestMatcher);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The register mapping.
|
||||
/// </summary>
|
||||
/// <param name="mapping">
|
||||
/// The mapping.
|
||||
/// </param>
|
||||
private void RegisterMapping(Mapping mapping)
|
||||
{
|
||||
lock (((ICollection)_mappings).SyncRoot)
|
||||
{
|
||||
_mappings.Add(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The log request.
|
||||
/// </summary>
|
||||
/// <param name="requestMessage">
|
||||
/// The request.
|
||||
/// </param>
|
||||
private void LogRequest(RequestMessage requestMessage)
|
||||
{
|
||||
lock (((ICollection)_requestLogs).SyncRoot)
|
||||
{
|
||||
_requestLogs.Add(requestMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The handle request.
|
||||
/// </summary>
|
||||
/// <param name="ctx">The HttpListenerContext.</param>
|
||||
private async void HandleRequestAsync(HttpListenerContext ctx)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
Task.Delay(_requestProcessingDelay).Wait();
|
||||
}
|
||||
|
||||
var request = _requestMapper.Map(ctx.Request);
|
||||
LogRequest(request);
|
||||
|
||||
try
|
||||
{
|
||||
var targetRoute = _mappings.FirstOrDefault(route => route.IsRequestHandled(request));
|
||||
if (targetRoute == null)
|
||||
{
|
||||
ctx.Response.StatusCode = 404;
|
||||
|
||||
byte[] content = Encoding.UTF8.GetBytes("No mapping found");
|
||||
ctx.Response.OutputStream.Write(content, 0, content.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
var response = await targetRoute.ResponseTo(request);
|
||||
_responseMapper.Map(response, ctx.Response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ctx.Response.StatusCode = 500;
|
||||
|
||||
byte[] content = Encoding.UTF8.GetBytes(ex.ToString());
|
||||
ctx.Response.OutputStream.Write(content, 0, content.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ctx.Response.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/WireMock.Net/Server/IRespondWithAProvider.cs
Normal file
16
src/WireMock.Net/Server/IRespondWithAProvider.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace WireMock.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// IRespondWithAProvider
|
||||
/// </summary>
|
||||
public interface IRespondWithAProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// The respond with.
|
||||
/// </summary>
|
||||
/// <param name="provider">
|
||||
/// The provider.
|
||||
/// </param>
|
||||
void RespondWith(IResponseProvider provider);
|
||||
}
|
||||
}
|
||||
42
src/WireMock.Net/Server/RespondWithAProvider.cs
Normal file
42
src/WireMock.Net/Server/RespondWithAProvider.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using WireMock.Matchers.Request;
|
||||
|
||||
namespace WireMock.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// The respond with a provider.
|
||||
/// </summary>
|
||||
internal class RespondWithAProvider : IRespondWithAProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// The _registration callback.
|
||||
/// </summary>
|
||||
private readonly RegistrationCallback _registrationCallback;
|
||||
|
||||
/// <summary>
|
||||
/// The _request matcher.
|
||||
/// </summary>
|
||||
private readonly IRequestMatcher _requestMatcher;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registrationCallback">The registration callback.</param>
|
||||
/// <param name="requestMatcher">The request matcher.</param>
|
||||
public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestMatcher)
|
||||
{
|
||||
_registrationCallback = registrationCallback;
|
||||
_requestMatcher = requestMatcher;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The respond with.
|
||||
/// </summary>
|
||||
/// <param name="provider">
|
||||
/// The provider.
|
||||
/// </param>
|
||||
public void RespondWith(IResponseProvider provider)
|
||||
{
|
||||
_registrationCallback(new Mapping(_requestMatcher, provider));
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/WireMock.Net/Util/WireMockList.cs
Normal file
50
src/WireMock.Net/Util/WireMockList.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace WireMock.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// A special List which overrides the ToString() to return first value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The generic type</typeparam>
|
||||
/// <seealso cref="List{T}" />
|
||||
public class WireMockList<T> : List<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WireMockList{T}"/> class.
|
||||
/// </summary>
|
||||
public WireMockList()
|
||||
{
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// 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(IEnumerable<T> collection) : base(collection)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
if (this != null && this.Any())
|
||||
return this.First().ToString();
|
||||
|
||||
return base.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
143
src/WireMock.Net/Validation/Check.cs
Normal file
143
src/WireMock.Net/Validation/Check.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
// Copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Shared/Check.cs
|
||||
namespace WireMock.Validation
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
[DebuggerStepThrough]
|
||||
internal static class Check
|
||||
{
|
||||
[ContractAnnotation("value:null => halt")]
|
||||
public static T Condition<T>([NoEnumeration] T value, [NotNull] Predicate<T> condition, [InvokerParameterName] [NotNull] string parameterName)
|
||||
{
|
||||
NotNull(condition, nameof(condition));
|
||||
NotNull(value, nameof(value));
|
||||
|
||||
if (!condition(value))
|
||||
{
|
||||
NotEmpty(parameterName, nameof(parameterName));
|
||||
|
||||
throw new ArgumentOutOfRangeException(parameterName);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[ContractAnnotation("value:null => halt")]
|
||||
public static T NotNull<T>([NoEnumeration] T value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
{
|
||||
if (ReferenceEquals(value, null))
|
||||
{
|
||||
NotEmpty(parameterName, nameof(parameterName));
|
||||
|
||||
throw new ArgumentNullException(parameterName);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[ContractAnnotation("value:null => halt")]
|
||||
public static T NotNull<T>(
|
||||
[NoEnumeration] T value,
|
||||
[InvokerParameterName] [NotNull] string parameterName,
|
||||
[NotNull] string propertyName)
|
||||
{
|
||||
if (ReferenceEquals(value, null))
|
||||
{
|
||||
NotEmpty(parameterName, nameof(parameterName));
|
||||
NotEmpty(propertyName, nameof(propertyName));
|
||||
|
||||
throw new ArgumentException(CoreStrings.ArgumentPropertyNull(propertyName, parameterName));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[ContractAnnotation("value:null => halt")]
|
||||
public static IList<T> NotEmpty<T>(IList<T> value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
{
|
||||
NotNull(value, parameterName);
|
||||
|
||||
if (value.Count == 0)
|
||||
{
|
||||
NotEmpty(parameterName, nameof(parameterName));
|
||||
|
||||
throw new ArgumentException(CoreStrings.CollectionArgumentIsEmpty(parameterName));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[ContractAnnotation("value:null => halt")]
|
||||
public static string NotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
{
|
||||
Exception e = null;
|
||||
if (ReferenceEquals(value, null))
|
||||
{
|
||||
e = new ArgumentNullException(parameterName);
|
||||
}
|
||||
else if (value.Trim().Length == 0)
|
||||
{
|
||||
e = new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName));
|
||||
}
|
||||
|
||||
if (e != null)
|
||||
{
|
||||
NotEmpty(parameterName, nameof(parameterName));
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static string NullButNotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
{
|
||||
if (!ReferenceEquals(value, null)
|
||||
&& (value.Length == 0))
|
||||
{
|
||||
NotEmpty(parameterName, nameof(parameterName));
|
||||
|
||||
throw new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static IList<T> HasNoNulls<T>(IList<T> value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
where T : class
|
||||
{
|
||||
NotNull(value, parameterName);
|
||||
|
||||
if (value.Any(e => e == null))
|
||||
{
|
||||
NotEmpty(parameterName, nameof(parameterName));
|
||||
|
||||
throw new ArgumentException(parameterName);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Type ValidEntityType(Type value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
{
|
||||
if (!value.GetTypeInfo().IsClass)
|
||||
{
|
||||
NotEmpty(parameterName, nameof(parameterName));
|
||||
|
||||
throw new ArgumentException(CoreStrings.InvalidEntityType(value, parameterName));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/WireMock.Net/Validation/CoreStrings.cs
Normal file
44
src/WireMock.Net/Validation/CoreStrings.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
// copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Microsoft.EntityFrameworkCore/Properties/CoreStrings.resx
|
||||
namespace WireMock.Validation
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
internal static class CoreStrings
|
||||
{
|
||||
/// <summary>
|
||||
/// The property '{property}' of the argument '{argument}' cannot be null.
|
||||
/// </summary>
|
||||
public static string ArgumentPropertyNull([CanBeNull] string property, [CanBeNull] string argument)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, $"The property '{property}' of the argument '{argument}' cannot be null.", property, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The string argument '{argumentName}' cannot be empty.
|
||||
/// </summary>
|
||||
public static string ArgumentIsEmpty([CanBeNull] string argumentName)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, $"The string argument '{argumentName}' cannot be empty.", argumentName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The entity type '{type}' provided for the argument '{argumentName}' must be a reference type.
|
||||
/// </summary>
|
||||
public static string InvalidEntityType([CanBeNull] Type type, [CanBeNull] string argumentName)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, $"The entity type '{type}' provided for the argument '{argumentName}' must be a reference type.", type, argumentName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The collection argument '{argumentName}' must contain at least one element.
|
||||
/// </summary>
|
||||
public static string CollectionArgumentIsEmpty([CanBeNull] string argumentName)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, $"The collection argument '{argumentName}' must contain at least one element.", argumentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/WireMock.Net/WireMock.Net.xproj
Normal file
19
src/WireMock.Net/WireMock.Net.xproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0.25420" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25420</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>d3804228-91f4-4502-9595-39584e5a01ad</ProjectGuid>
|
||||
<RootNamespace>WireMock</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
15
src/WireMock.Net/netstandard1.3.txt
Normal file
15
src/WireMock.Net/netstandard1.3.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
,
|
||||
"netstandard1.3": {
|
||||
"buildOptions": { "define": [ "NETSTANDARD" ] },
|
||||
"imports": [
|
||||
"dotnet5.4"
|
||||
],
|
||||
"dependencies": {
|
||||
"System.Collections.Concurrent": "4.3.0",
|
||||
"System.Diagnostics.Tools": "4.3.0",
|
||||
"System.Linq": "4.3.0",
|
||||
"System.Net.Http": "4.3.0",
|
||||
"System.Net.Sockets": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
}
|
||||
43
src/WireMock.Net/project.json
Normal file
43
src/WireMock.Net/project.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"version": "1.0.0.0",
|
||||
"title": "WireMock.Net",
|
||||
"description": "Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.",
|
||||
"authors": [ "Alexandre Victoor", "Stef Heyenrath" ],
|
||||
|
||||
"packOptions": {
|
||||
"summary": "Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.",
|
||||
"tags": [ "tdd", "mock", "http", "wiremock", "test", "server", "unittest" ],
|
||||
"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"
|
||||
},
|
||||
|
||||
"buildOptions": {
|
||||
"xmlDoc": true
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"JetBrains.Annotations": {
|
||||
"version": "10.2.1",
|
||||
"type": "build"
|
||||
},
|
||||
"Handlebars.Net": "1.8.0",
|
||||
"Newtonsoft.Json": "6.0.8",
|
||||
"XPath2": "1.0.3.1"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"net45": {
|
||||
"dependencies": {
|
||||
},
|
||||
"frameworkAssemblies": {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user