Initial code (copy)

This commit is contained in:
Stef Heyenrath
2017-01-17 22:44:21 +01:00
parent 4ab93896d7
commit eeaeeb2c61
47 changed files with 3311 additions and 1 deletions

View File

@@ -0,0 +1,57 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The composite request spec.
/// </summary>
public class CompositeRequestSpec : ISpecifyRequests
{
/// <summary>
/// The _request specs.
/// </summary>
private readonly IEnumerable<ISpecifyRequests> _requestSpecs;
/// <summary>
/// Initializes a new instance of the <see cref="CompositeRequestSpec"/> class.
/// The constructor.
/// </summary>
/// <param name="requestSpecs">
/// The <see cref="IEnumerable&lt;ISpecifyRequests&gt;"/> request specs.
/// </param>
public CompositeRequestSpec(IEnumerable<ISpecifyRequests> requestSpecs)
{
_requestSpecs = requestSpecs;
}
/// <summary>
/// The is satisfied by.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy(Request request)
{
return _requestSpecs.All(spec => spec.IsSatisfiedBy(request));
}
}
}

View File

@@ -0,0 +1,311 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using WireMock.Http;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The fluent mock server.
/// </summary>
public class FluentMockServer
{
/// <summary>
/// The _http server.
/// </summary>
private readonly TinyHttpServer _httpServer;
/// <summary>
/// The _routes.
/// </summary>
private readonly IList<Route> _routes = new List<Route>();
/// <summary>
/// The _request logs.
/// </summary>
private readonly IList<Request> _requestLogs = new List<Request>();
/// <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>
/// Initializes a new instance of the <see cref="FluentMockServer"/> class.
/// </summary>
/// <param name="port">
/// The port.
/// </param>
/// <param name="ssl">
/// The SSL support.
/// </param>
private FluentMockServer(int port, bool ssl)
{
string protocol = ssl ? "https" : "http";
_httpServer = new TinyHttpServer(protocol + "://localhost:" + port + "/", HandleRequest);
Port = port;
_httpServer.Start();
}
/// <summary>
/// The RespondWithAProvider interface.
/// </summary>
public interface IRespondWithAProvider
{
/// <summary>
/// The respond with.
/// </summary>
/// <param name="provider">
/// The provider.
/// </param>
void RespondWith(IProvideResponses provider);
}
/// <summary>
/// Gets the port.
/// </summary>
public int Port { get; }
/// <summary>
/// Gets the request logs.
/// </summary>
public IEnumerable<Request> RequestLogs
{
get
{
lock (((ICollection)_requestLogs).SyncRoot)
{
return new ReadOnlyCollection<Request>(_requestLogs);
}
}
}
/// <summary>
/// The start.
/// </summary>
/// <param name="port">
/// The port.
/// </param>
/// <param name="ssl">
/// The SSL support.
/// </param>
/// <returns>
/// The <see cref="FluentMockServer"/>.
/// </returns>
public static FluentMockServer Start(int port = 0, bool ssl = false)
{
if (port == 0)
{
port = Ports.FindFreeTcpPort();
}
return new FluentMockServer(port, ssl);
}
/// <summary>
/// The reset.
/// </summary>
public void Reset()
{
lock (((ICollection)_requestLogs).SyncRoot)
{
_requestLogs.Clear();
}
lock (((ICollection)_routes).SyncRoot)
{
_routes.Clear();
}
}
/// <summary>
/// The search logs for.
/// </summary>
/// <param name="spec">
/// The spec.
/// </param>
/// <returns>
/// The <see cref="IEnumerable"/>.
/// </returns>
public IEnumerable<Request> SearchLogsFor(ISpecifyRequests spec)
{
lock (((ICollection)_requestLogs).SyncRoot)
{
return _requestLogs.Where(spec.IsSatisfiedBy);
}
}
/// <summary>
/// The add request processing delay.
/// </summary>
/// <param name="delay">
/// The delay.
/// </param>
public void AddRequestProcessingDelay(TimeSpan delay)
{
lock (_syncRoot)
{
_requestProcessingDelay = delay;
}
}
/// <summary>
/// The stop.
/// </summary>
public void Stop()
{
_httpServer.Stop();
}
/// <summary>
/// The given.
/// </summary>
/// <param name="requestSpec">
/// The request spec.
/// </param>
/// <returns>
/// The <see cref="IRespondWithAProvider"/>.
/// </returns>
public IRespondWithAProvider Given(ISpecifyRequests requestSpec)
{
return new RespondWithAProvider(RegisterRoute, requestSpec);
}
/// <summary>
/// The register route.
/// </summary>
/// <param name="route">
/// The route.
/// </param>
private void RegisterRoute(Route route)
{
lock (((ICollection)_routes).SyncRoot)
{
_routes.Add(route);
}
}
/// <summary>
/// The log request.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
private void LogRequest(Request request)
{
lock (((ICollection)_requestLogs).SyncRoot)
{
_requestLogs.Add(request);
}
}
/// <summary>
/// The handle request.
/// </summary>
/// <param name="ctx">
/// The context.
/// </param>
private async void HandleRequest(HttpListenerContext ctx)
{
lock (_syncRoot)
{
Task.Delay(_requestProcessingDelay).Wait();
}
var request = _requestMapper.Map(ctx.Request);
LogRequest(request);
var targetRoute = _routes.FirstOrDefault(route => route.IsRequestHandled(request));
if (targetRoute == null)
{
ctx.Response.StatusCode = 404;
var content = Encoding.UTF8.GetBytes("<html><body>Mock Server: page not found</body></html>");
ctx.Response.OutputStream.Write(content, 0, content.Length);
}
else
{
var response = await targetRoute.ResponseTo(request);
_responseMapper.Map(response, ctx.Response);
}
ctx.Response.Close();
}
/// <summary>
/// The respond with a provider.
/// </summary>
private class RespondWithAProvider : IRespondWithAProvider
{
/// <summary>
/// The _registration callback.
/// </summary>
private readonly RegistrationCallback _registrationCallback;
/// <summary>
/// The _request spec.
/// </summary>
private readonly ISpecifyRequests _requestSpec;
/// <summary>
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
/// </summary>
/// <param name="registrationCallback">
/// The registration callback.
/// </param>
/// <param name="requestSpec">
/// The request spec.
/// </param>
public RespondWithAProvider(RegistrationCallback registrationCallback, ISpecifyRequests requestSpec)
{
_registrationCallback = registrationCallback;
_requestSpec = requestSpec;
}
/// <summary>
/// The respond with.
/// </summary>
/// <param name="provider">
/// The provider.
/// </param>
public void RespondWith(IProvideResponses provider)
{
_registrationCallback(new Route(_requestSpec, provider));
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Sockets;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1650:ElementDocumentationMustBeSpelledCorrectly",
Justification = "Reviewed. Suppression is OK here.")]
namespace WireMock.Http
{
/// <summary>
/// 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>
// ReSharper disable once StyleCop.SA1650
public static int FindFreeTcpPort()
{
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
}
}

View File

@@ -0,0 +1,98 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock.Http
{
/// <summary>
/// The tiny http server.
/// </summary>
public class TinyHttpServer
{
/// <summary>
/// The _http handler.
/// </summary>
private readonly Action<HttpListenerContext> _httpHandler;
/// <summary>
/// The _listener.
/// </summary>
private readonly HttpListener _listener;
/// <summary>
/// The cancellation token source.
/// </summary>
private CancellationTokenSource _cts;
/// <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;
// .Net Framework is not supportted on XP or Server 2003, so no need for the check
/*if (!HttpListener.IsSupported)
{
Console.WriteLine("Windows XP SP2 or Server 2003 is required to use the HttpListener class.");
return;
}*/
// Create a listener.
_listener = new HttpListener();
_listener.Prefixes.Add(urlPrefix);
}
/// <summary>
/// The start.
/// </summary>
public void Start()
{
_listener.Start();
_cts = new CancellationTokenSource();
Task.Run(
async () =>
{
using (_listener)
{
while (!_cts.Token.IsCancellationRequested)
{
HttpListenerContext context = await _listener.GetContextAsync();
_httpHandler(context);
}
}
},
_cts.Token);
}
/// <summary>
/// The stop.
/// </summary>
public void Stop()
{
_cts.Cancel();
}
}
}

View File

@@ -0,0 +1,68 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
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="Request"/>.
/// </returns>
public Request Map(HttpListenerRequest listenerRequest)
{
var path = listenerRequest.Url.AbsolutePath;
var query = listenerRequest.Url.Query;
var verb = listenerRequest.HttpMethod;
var body = GetRequestBody(listenerRequest);
var listenerHeaders = listenerRequest.Headers;
var headers = listenerHeaders.AllKeys.ToDictionary(k => k, k => listenerHeaders[k]);
return new Request(path, query, verb, body, headers);
}
/// <summary>
/// The get request body.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
private string GetRequestBody(HttpListenerRequest request)
{
if (!request.HasEntityBody)
{
return null;
}
using (var body = request.InputStream)
{
using (var reader = new StreamReader(body, request.ContentEncoding))
{
return reader.ReadToEnd();
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Text;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
namespace WireMock
{
/// <summary>
/// The http listener response mapper.
/// </summary>
public class HttpListenerResponseMapper
{
/// <summary>
/// The map.
/// </summary>
/// <param name="response">
/// The response.
/// </param>
/// <param name="result">
/// The result.
/// </param>
public void Map(Response response, HttpListenerResponse result)
{
result.StatusCode = response.StatusCode;
response.Headers.ToList().ForEach(pair => result.AddHeader(pair.Key, pair.Value));
if (response.Body != null)
{
var content = Encoding.UTF8.GetBytes(response.Body);
result.OutputStream.Write(content, 0, content.Length);
}
}
}
}

View File

@@ -0,0 +1,27 @@
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
namespace WireMock
{
/// <summary>
/// The ProvideResponses interface.
/// </summary>
public interface IProvideResponses
{
/// <summary>
/// The provide response.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
Task<Response> ProvideResponse(Request request);
}
}

View File

@@ -0,0 +1,26 @@
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
namespace WireMock
{
/// <summary>
/// The SpecifyRequests interface.
/// </summary>
public interface ISpecifyRequests
{
/// <summary>
/// The is satisfied by.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
bool IsSatisfiedBy(Request request);
}
}

138
src/WireMock/Request.cs Normal file
View File

@@ -0,0 +1,138 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1650:ElementDocumentationMustBeSpelledCorrectly",
Justification = "Reviewed. Suppression is OK here.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The request.
/// </summary>
public class Request
{
/// <summary>
/// The _params.
/// </summary>
private readonly Dictionary<string, List<string>> _params = new Dictionary<string, List<string>>();
/// <summary>
/// Initializes a new instance of the <see cref="Request"/> class.
/// </summary>
/// <param name="path">
/// The path.
/// </param>
/// <param name="query">
/// The query.
/// </param>
/// <param name="verb">
/// The verb.
/// </param>
/// <param name="body">
/// The body.
/// </param>
/// <param name="headers">
/// The headers.
/// </param>
public Request(string path, string query, string verb, string body, IDictionary<string, string> headers)
{
if (!string.IsNullOrEmpty(query))
{
if (query.StartsWith("?"))
{
query = query.Substring(1);
}
_params = query.Split('&').Aggregate(
new Dictionary<string, List<string>>(),
(dict, term) =>
{
var key = term.Split('=')[0];
if (!dict.ContainsKey(key))
{
dict.Add(key, new List<string>());
}
dict[key].Add(term.Split('=')[1]);
return dict;
});
}
Path = path;
Headers = headers.ToDictionary(kv => kv.Key.ToLower(), kv => kv.Value.ToLower());
Verb = verb.ToLower();
Body = body?.Trim() ?? string.Empty;
}
/// <summary>
/// Gets the url.
/// </summary>
public string Url
{
get
{
if (!_params.Any())
{
return Path;
}
return Path + "?" + string.Join("&", _params.SelectMany(kv => kv.Value.Select(value => kv.Key + "=" + value)));
}
}
/// <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 body.
/// </summary>
public string Body { get; }
/// <summary>
/// The get parameter.
/// </summary>
/// <param name="key">
/// The key.
/// </param>
/// <returns>
/// The parameter.
/// </returns>
public List<string> GetParameter(string key)
{
if (_params.ContainsKey(key))
{
return _params[key];
}
return new List<string>();
}
}
}

View File

@@ -0,0 +1,54 @@
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The request body spec.
/// </summary>
public class RequestBodySpec : ISpecifyRequests
{
/// <summary>
/// The _body.
/// </summary>
private readonly string _body;
/// <summary>
/// Initializes a new instance of the <see cref="RequestBodySpec"/> class.
/// </summary>
/// <param name="body">
/// The body.
/// </param>
public RequestBodySpec(string body)
{
_body = body.Trim();
}
/// <summary>
/// The is satisfied by.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy(Request request)
{
return WildcardPatternMatcher.MatchWildcardString(_body, request.Body.Trim());
}
}
}

View File

@@ -0,0 +1,64 @@
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The request header spec.
/// </summary>
public class RequestHeaderSpec : ISpecifyRequests
{
/// <summary>
/// The _name.
/// </summary>
private readonly string _name;
/// <summary>
/// The _pattern.
/// </summary>
private readonly string _pattern;
/// <summary>
/// Initializes a new instance of the <see cref="RequestHeaderSpec"/> class.
/// </summary>
/// <param name="name">
/// The name.
/// </param>
/// <param name="pattern">
/// The pattern.
/// </param>
public RequestHeaderSpec(string name, string pattern)
{
_name = name.ToLower();
_pattern = pattern.ToLower();
}
/// <summary>
/// The is satisfied by.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy(Request request)
{
string headerValue = request.Headers[_name];
return WildcardPatternMatcher.MatchWildcardString(_pattern, headerValue);
}
}
}

View File

@@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The request parameters spec.
/// </summary>
public class RequestParamSpec : ISpecifyRequests
{
/// <summary>
/// The _key.
/// </summary>
private readonly string _key;
/// <summary>
/// The _values.
/// </summary>
private readonly List<string> _values;
/// <summary>
/// Initializes a new instance of the <see cref="RequestParamSpec"/> class.
/// </summary>
/// <param name="key">
/// The key.
/// </param>
/// <param name="values">
/// The values.
/// </param>
public RequestParamSpec(string key, List<string> values)
{
_key = key;
_values = values;
}
/// <summary>
/// The is satisfied by.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy(Request request)
{
return request.GetParameter(_key).Intersect(_values).Count() == _values.Count;
}
}
}

View File

@@ -0,0 +1,54 @@
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The request path spec.
/// </summary>
public class RequestPathSpec : ISpecifyRequests
{
/// <summary>
/// The _path.
/// </summary>
private readonly string _path;
/// <summary>
/// Initializes a new instance of the <see cref="RequestPathSpec"/> class.
/// </summary>
/// <param name="path">
/// The path.
/// </param>
public RequestPathSpec(string path)
{
_path = path;
}
/// <summary>
/// The is satisfied by.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy(Request request)
{
return WildcardPatternMatcher.MatchWildcardString(_path, request.Path);
}
}
}

View File

@@ -0,0 +1,123 @@
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
namespace WireMock
{
/// <summary>
/// The VerbRequestBuilder interface.
/// </summary>
public interface IVerbRequestBuilder : ISpecifyRequests, IHeadersRequestBuilder
{
/// <summary>
/// The using get.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
IHeadersRequestBuilder UsingGet();
/// <summary>
/// The using post.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
IHeadersRequestBuilder UsingPost();
/// <summary>
/// The using put.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
IHeadersRequestBuilder UsingPut();
/// <summary>
/// The using head.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
IHeadersRequestBuilder UsingHead();
/// <summary>
/// The using any verb.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
IHeadersRequestBuilder UsingAnyVerb();
/// <summary>
/// The using verb.
/// </summary>
/// <param name="verb">
/// The verb.
/// </param>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
IHeadersRequestBuilder UsingVerb(string verb);
}
/// <summary>
/// The HeadersRequestBuilder interface.
/// </summary>
public interface IHeadersRequestBuilder : IBodyRequestBuilder, ISpecifyRequests, IParamsRequestBuilder
{
/// <summary>
/// The with header.
/// </summary>
/// <param name="name">
/// The name.
/// </param>
/// <param name="value">
/// The value.
/// </param>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
IHeadersRequestBuilder WithHeader(string name, string value);
}
/// <summary>
/// The BodyRequestBuilder interface.
/// </summary>
public interface IBodyRequestBuilder
{
/// <summary>
/// The with body.
/// </summary>
/// <param name="body">
/// The body.
/// </param>
/// <returns>
/// The <see cref="ISpecifyRequests"/>.
/// </returns>
ISpecifyRequests WithBody(string body);
}
/// <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="ISpecifyRequests"/>.
/// </returns>
ISpecifyRequests WithParam(string key, params string[] values);
}
}

View File

@@ -0,0 +1,54 @@
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The request url spec.
/// </summary>
public class RequestUrlSpec : ISpecifyRequests
{
/// <summary>
/// The _url.
/// </summary>
private readonly string _url;
/// <summary>
/// Initializes a new instance of the <see cref="RequestUrlSpec"/> class.
/// </summary>
/// <param name="url">
/// The url.
/// </param>
public RequestUrlSpec(string url)
{
_url = url;
}
/// <summary>
/// The is satisfied by.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy(Request request)
{
return WildcardPatternMatcher.MatchWildcardString(_url, request.Url);
}
}
}

View File

@@ -0,0 +1,54 @@
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The request verb spec.
/// </summary>
internal class RequestVerbSpec : ISpecifyRequests
{
/// <summary>
/// The _verb.
/// </summary>
private readonly string _verb;
/// <summary>
/// Initializes a new instance of the <see cref="RequestVerbSpec"/> class.
/// </summary>
/// <param name="verb">
/// The verb.
/// </param>
public RequestVerbSpec(string verb)
{
_verb = verb.ToLower();
}
/// <summary>
/// The is satisfied by.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsSatisfiedBy(Request request)
{
return request.Verb == _verb;
}
}
}

205
src/WireMock/Requests.cs Normal file
View File

@@ -0,0 +1,205 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1126:PrefixCallsCorrectly",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The requests.
/// </summary>
public class Requests : CompositeRequestSpec, IVerbRequestBuilder, IHeadersRequestBuilder, IParamsRequestBuilder
{
/// <summary>
/// The _request specs.
/// </summary>
private readonly IList<ISpecifyRequests> _requestSpecs;
/// <summary>
/// Initializes a new instance of the <see cref="Requests"/> class.
/// </summary>
/// <param name="requestSpecs">
/// The request specs.
/// </param>
private Requests(IList<ISpecifyRequests> requestSpecs) : base(requestSpecs)
{
_requestSpecs = requestSpecs;
}
/// <summary>
/// The with url.
/// </summary>
/// <param name="url">
/// The url.
/// </param>
/// <returns>
/// The <see cref="IVerbRequestBuilder"/>.
/// </returns>
public static IVerbRequestBuilder WithUrl(string url)
{
var specs = new List<ISpecifyRequests>();
var requests = new Requests(specs);
specs.Add(new RequestUrlSpec(url));
return requests;
}
/// <summary>
/// The with path.
/// </summary>
/// <param name="path">
/// The path.
/// </param>
/// <returns>
/// The <see cref="IVerbRequestBuilder"/>.
/// </returns>
public static IVerbRequestBuilder WithPath(string path)
{
var specs = new List<ISpecifyRequests>();
var requests = new Requests(specs);
specs.Add(new RequestPathSpec(path));
return requests;
}
/// <summary>
/// The using get.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
public IHeadersRequestBuilder UsingGet()
{
_requestSpecs.Add(new RequestVerbSpec("get"));
return this;
}
/// <summary>
/// The using post.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
public IHeadersRequestBuilder UsingPost()
{
_requestSpecs.Add(new RequestVerbSpec("post"));
return this;
}
/// <summary>
/// The using put.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
public IHeadersRequestBuilder UsingPut()
{
_requestSpecs.Add(new RequestVerbSpec("put"));
return this;
}
/// <summary>
/// The using head.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
public IHeadersRequestBuilder UsingHead()
{
_requestSpecs.Add(new RequestVerbSpec("head"));
return this;
}
/// <summary>
/// The using any verb.
/// </summary>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
public IHeadersRequestBuilder UsingAnyVerb()
{
return this;
}
/// <summary>
/// The using verb.
/// </summary>
/// <param name="verb">
/// The verb.
/// </param>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
public IHeadersRequestBuilder UsingVerb(string verb)
{
_requestSpecs.Add(new RequestVerbSpec(verb));
return this;
}
/// <summary>
/// The with body.
/// </summary>
/// <param name="body">
/// The body.
/// </param>
/// <returns>
/// The <see cref="ISpecifyRequests"/>.
/// </returns>
public ISpecifyRequests WithBody(string body)
{
_requestSpecs.Add(new RequestBodySpec(body));
return this;
}
/// <summary>
/// The with parameters.
/// </summary>
/// <param name="key">
/// The key.
/// </param>
/// <param name="values">
/// The values.
/// </param>
/// <returns>
/// The <see cref="ISpecifyRequests"/>.
/// </returns>
public ISpecifyRequests WithParam(string key, params string[] values)
{
_requestSpecs.Add(new RequestParamSpec(key, values.ToList()));
return this;
}
/// <summary>
/// The with header.
/// </summary>
/// <param name="name">
/// The name.
/// </param>
/// <param name="value">
/// The value.
/// </param>
/// <returns>
/// The <see cref="IHeadersRequestBuilder"/>.
/// </returns>
public IHeadersRequestBuilder WithHeader(string name, string value)
{
_requestSpecs.Add(new RequestHeaderSpec(name, value));
return this;
}
}
}

92
src/WireMock/Response.cs Normal file
View File

@@ -0,0 +1,92 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The response.
/// </summary>
public class Response
{
/// <summary>
/// The _headers.
/// </summary>
private readonly IDictionary<string, string> _headers = new ConcurrentDictionary<string, string>();
/// <summary>
/// The status code.
/// </summary>
private volatile int statusCode = 200;
/// <summary>
/// The body.
/// </summary>
private volatile string body;
/// <summary>
/// Gets the headers.
/// </summary>
public IDictionary<string, string> Headers => _headers;
/// <summary>
/// Gets or sets the status code.
/// </summary>
public int StatusCode
{
get
{
return statusCode;
}
set
{
statusCode = value;
}
}
/// <summary>
/// Gets or sets the body.
/// </summary>
public string Body
{
get
{
return body;
}
set
{
body = value;
}
}
/// <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);
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
namespace WireMock
{
/// <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(string name, string value);
}
/// <summary>
/// The BodyResponseBuilder interface.
/// </summary>
public interface IBodyResponseBuilder : IDelayResponseBuilder
{
/// <summary>
/// The with body.
/// </summary>
/// <param name="body">
/// The body.
/// </param>
/// <returns>
/// The <see cref="IDelayResponseBuilder"/>.
/// </returns>
IDelayResponseBuilder WithBody(string body);
}
/// <summary>
/// The DelayResponseBuilder interface.
/// </summary>
public interface IDelayResponseBuilder : IProvideResponses
{
/// <summary>
/// The after delay.
/// </summary>
/// <param name="delay">
/// The delay.
/// </param>
/// <returns>
/// The <see cref="IProvideResponses"/>.
/// </returns>
IProvideResponses AfterDelay(TimeSpan delay);
}
}

143
src/WireMock/Responses.cs Normal file
View File

@@ -0,0 +1,143 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The responses.
/// </summary>
public class Responses : IHeadersResponseBuilder
{
/// <summary>
/// The _response.
/// </summary>
private readonly Response _response;
/// <summary>
/// The _delay.
/// </summary>
private TimeSpan _delay = TimeSpan.Zero;
/// <summary>
/// Initializes a new instance of the <see cref="Responses"/> class.
/// </summary>
/// <param name="response">
/// The response.
/// </param>
public Responses(Response response)
{
_response = response;
}
/// <summary>
/// The with Success status code.
/// </summary>
/// <returns>The <see cref="IHeadersResponseBuilder"/>.</returns>
public static IHeadersResponseBuilder WithSuccess()
{
return WithStatusCode(200);
}
/// <summary>
/// The with NotFound status code.
/// </summary>
/// <returns>The <see cref="IHeadersResponseBuilder"/>.</returns>
public static IHeadersResponseBuilder WithNotFound()
{
return WithStatusCode(404);
}
/// <summary>
/// The with status code.
/// </summary>
/// <param name="code">
/// The code.
/// </param>
/// <returns>
/// The <see cref="IHeadersResponseBuilder"/>.
/// </returns>
public static IHeadersResponseBuilder WithStatusCode(int code)
{
var response = new Response { StatusCode = code };
return new Responses(response);
}
/// <summary>
/// The provide response.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public async Task<Response> ProvideResponse(Request request)
{
await Task.Delay(_delay);
return _response;
}
/// <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)
{
_response.AddHeader(name, value);
return this;
}
/// <summary>
/// The with body.
/// </summary>
/// <param name="body">
/// The body.
/// </param>
/// <returns>
/// The <see cref="IDelayResponseBuilder"/>.
/// </returns>
public IDelayResponseBuilder WithBody(string body)
{
_response.Body = body;
return this;
}
/// <summary>
/// The after delay.
/// </summary>
/// <param name="delay">
/// The delay.
/// </param>
/// <returns>
/// The <see cref="IProvideResponses"/>.
/// </returns>
public IProvideResponses AfterDelay(TimeSpan delay)
{
_delay = delay;
return this;
}
}
}

78
src/WireMock/Route.cs Normal file
View File

@@ -0,0 +1,78 @@
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
[module:
SuppressMessage("StyleCop.CSharp.ReadabilityRules",
"SA1101:PrefixLocalCallsWithThis",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.NamingRules",
"SA1309:FieldNamesMustNotBeginWithUnderscore",
Justification = "Reviewed. Suppression is OK here, as it conflicts with internal naming rules.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
// ReSharper disable ArrangeThisQualifier
// ReSharper disable InconsistentNaming
namespace WireMock
{
/// <summary>
/// The route.
/// </summary>
public class Route
{
/// <summary>
/// The _request spec.
/// </summary>
private readonly ISpecifyRequests _requestSpec;
/// <summary>
/// The _provider.
/// </summary>
private readonly IProvideResponses _provider;
/// <summary>
/// Initializes a new instance of the <see cref="Route"/> class.
/// </summary>
/// <param name="requestSpec">
/// The request spec.
/// </param>
/// <param name="provider">
/// The provider.
/// </param>
public Route(ISpecifyRequests requestSpec, IProvideResponses provider)
{
_requestSpec = requestSpec;
_provider = provider;
}
/// <summary>
/// The response to.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="Task"/>.
/// </returns>
public Task<Response> ResponseTo(Request request)
{
return _provider.ProvideResponse(request);
}
/// <summary>
/// The is request handled.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool IsRequestHandled(Request request)
{
return _requestSpec.IsSatisfiedBy(request);
}
}
}

View File

@@ -0,0 +1,17 @@
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
namespace WireMock
{
/// <summary>
/// The registration callback.
/// </summary>
/// <param name="route">
/// The route.
/// </param>
public delegate void RegistrationCallback(Route route);
}

View File

@@ -0,0 +1,74 @@
using System.Diagnostics.CodeAnalysis;
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1633:FileMustHaveHeader",
Justification = "Reviewed. Suppression is OK here, as unknown copyright and company.")]
[module:
SuppressMessage("StyleCop.CSharp.DocumentationRules",
"SA1650:ElementDocumentationMustBeSpelledCorrectly",
Justification = "Reviewed. Suppression is OK here.")]
namespace WireMock
{
/// <summary>
/// The wildcard pattern matcher.
/// </summary>
public static class WildcardPatternMatcher
{
/// <summary>
/// The match wildcard string.
/// </summary>
/// <param name="pattern">
/// The pattern.
/// </param>
/// <param name="input">
/// The input.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
/// <remarks>
/// Copy/paste from http://www.codeproject.com/Tips/57304/Use-wildcard-characters-and-to-compare-strings
/// </remarks>
public static bool MatchWildcardString(string pattern, string input)
{
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] == '*')
{
return MatchWildcardString(pattern.Substring(1), input) || MatchWildcardString(pattern, input.Substring(1));
}
if (pattern[pattern.Length - 1] == '*')
{
return MatchWildcardString(pattern.Substring(0, pattern.Length - 1), input) || MatchWildcardString(pattern, input.Substring(0, input.Length - 1));
}
return pattern[0] == input[0] && MatchWildcardString(pattern.Substring(1), input.Substring(1));
}
}
}

View 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>

View 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"
}
}

37
src/WireMock/project.json Normal file
View File

@@ -0,0 +1,37 @@
{
"version": "1.0.0.9",
"title": "WireMock.Net",
"description": "xxxx",
"authors": [ "Alexandre Victoor", "Stef Heyenrath" ],
"packOptions": {
"summary": "This is a .NET Core port of the the Microsoft assembly for the .Net 4.0 Dynamic language functionality.",
"tags": [ "system", "linq", "dynamic", "core" ],
"owners": [ "Stef Heyenrath" ],
"repository": {
"type": "git",
"url": "https://github.com/StefH/WireMock.Net"
},
"projectUrl": "https://github.com/StefH/WireMock.Net",
"licenseUrl": "https://github.com/StefH/WireMock.Net/blob/master/licence.txt",
"releaseNotes": ""
},
"buildOptions": {
"xmlDoc": true
},
"dependencies": {
"JetBrains.Annotations": {
"version": "10.2.1",
"type": "build"
}
},
"frameworks": {
"net45": {
"frameworkAssemblies": {
}
}
}
}