Fix WithBody when using Pact and added more nullable annotations (#783)

* More nullable annotations

* .

* .

* FIX

* pact

* .

* p

* xxx

* ...

* auth

* array

* ...
This commit is contained in:
Stef Heyenrath
2022-08-11 10:57:33 +02:00
committed by GitHub
parent b1af37f044
commit d2a1d0f069
87 changed files with 2578 additions and 2455 deletions
+1
View File
@@ -25,6 +25,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Victoor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Webhook/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Webhooks/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=wiremock/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=wiremockserver/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=xunit/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>
@@ -1,24 +1,23 @@
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// WebProxy settings
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class WebProxyModel
{
/// <summary>
/// WebProxy settings
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class WebProxyModel
{
/// <summary>
/// A string instance that contains the address of the proxy server.
/// </summary>
public string Address { get; set; }
public string Address { get; set; } = null!;
/// <summary>
/// The user name associated with the credentials.
/// The user name associated with the credentials. [optional]
/// </summary>
public string UserName { get; set; }
public string? UserName { get; set; }
/// <summary>
/// The password for the user name associated with the credentials.
/// The password for the user name associated with the credentials. [optional]
/// </summary>
public string Password { get; set; }
}
public string? Password { get; set; }
}
@@ -1,14 +1,13 @@
using System.Collections.Generic;
using WireMock.Types;
namespace WireMock.Admin.Mappings
namespace WireMock.Admin.Mappings;
/// <summary>
/// RequestModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class WebhookRequestModel
{
/// <summary>
/// RequestModel
/// </summary>
[FluentBuilder.AutoGenerateBuilder]
public class WebhookRequestModel
{
/// <summary>
/// Gets or sets the Url.
/// </summary>
@@ -42,11 +41,10 @@ namespace WireMock.Admin.Mappings
/// <summary>
/// Gets the type of the transformer.
/// </summary>
public string TransformerType { get; set; }
public string? TransformerType { get; set; }
/// <summary>
/// The ReplaceNodeOptions to use when transforming a JSON node.
/// </summary>
public string TransformerReplaceNodeOptions { get; set; }
}
public string? TransformerReplaceNodeOptions { get; set; }
}
@@ -63,12 +63,12 @@ public interface IRequestMessage
/// <summary>
/// Gets the headers.
/// </summary>
IDictionary<string, WireMockList<string>> Headers { get; }
IDictionary<string, WireMockList<string>>? Headers { get; }
/// <summary>
/// Gets the cookies.
/// </summary>
IDictionary<string, string> Cookies { get; }
IDictionary<string, string>? Cookies { get; }
/// <summary>
/// Gets the query.
@@ -3,27 +3,27 @@ using WireMock.ResponseBuilders;
using WireMock.Types;
using WireMock.Util;
namespace WireMock
namespace WireMock;
/// <summary>
/// IResponseMessage
/// </summary>
public interface IResponseMessage
{
/// <summary>
/// IResponseMessage
/// </summary>
public interface IResponseMessage
{
/// <summary>
/// The Body.
/// </summary>
IBodyData? BodyData { get; }
/// <summary>
/// Gets the body destination (SameAsSource, String or Bytes).
/// Gets the body destination (Null, SameAsSource, String or Bytes).
/// </summary>
string BodyDestination { get; }
string? BodyDestination { get; }
/// <summary>
/// Gets or sets the body.
/// </summary>
string BodyOriginal { get; }
string? BodyOriginal { get; }
/// <summary>
/// Gets the Fault percentage.
@@ -43,7 +43,7 @@ namespace WireMock
/// <summary>
/// Gets or sets the status code.
/// </summary>
object StatusCode { get; }
object? StatusCode { get; }
/// <summary>
/// Adds the header.
@@ -58,5 +58,4 @@ namespace WireMock
/// <param name="name">The name.</param>
/// <param name="values">The values.</param>
void AddHeader(string name, params string[] values);
}
}
@@ -1,13 +1,13 @@
using System;
using System;
using WireMock.Matchers.Request;
namespace WireMock.Logging
namespace WireMock.Logging;
/// <summary>
/// ILogEntry
/// </summary>
public interface ILogEntry
{
/// <summary>
/// ILogEntry
/// </summary>
public interface ILogEntry
{
/// <summary>
/// Gets the unique identifier.
/// </summary>
@@ -21,7 +21,7 @@ namespace WireMock.Logging
/// <summary>
/// Gets the mapping unique title.
/// </summary>
string MappingTitle { get; }
string? MappingTitle { get; }
/// <summary>
/// Gets the partial mapping unique identifier.
@@ -31,7 +31,7 @@ namespace WireMock.Logging
/// <summary>
/// Gets the partial mapping unique title.
/// </summary>
string PartialMappingTitle { get; }
string? PartialMappingTitle { get; }
/// <summary>
/// Gets the partial match result.
@@ -52,5 +52,4 @@ namespace WireMock.Logging
/// Gets the response message.
/// </summary>
IResponseMessage ResponseMessage { get; }
}
}
@@ -1,13 +1,12 @@
namespace WireMock.Models
namespace WireMock.Models;
/// <summary>
/// IWebhook
/// </summary>
public interface IWebhook
{
/// <summary>
/// IWebhook
/// </summary>
public interface IWebhook
{
/// <summary>
/// Request
/// </summary>
IWebhookRequest Request { get; set; }
}
}
@@ -59,7 +59,7 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
MatchOperator = matchOperator;
}
public double IsMatch(string input)
public double IsMatch(string? input)
{
return IsMatchInternal(input);
}
@@ -1,4 +1,5 @@
#if !NETSTANDARD1_3
using System;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.Text.RegularExpressions;
@@ -6,17 +7,18 @@ using AnyOfTypes;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Stef.Validation;
using WireMock.Matchers;
using WireMock.Models;
namespace WireMock.Authentication
namespace WireMock.Authentication;
/// <summary>
/// https://www.c-sharpcorner.com/article/how-to-validate-azure-ad-token-using-console-application/
/// https://stackoverflow.com/questions/38684865/validation-of-an-azure-ad-bearer-token-in-a-console-application
/// </summary>
internal class AzureADAuthenticationMatcher : IStringMatcher
{
/// <summary>
/// https://www.c-sharpcorner.com/article/how-to-validate-azure-ad-token-using-console-application/
/// https://stackoverflow.com/questions/38684865/validation-of-an-azure-ad-bearer-token-in-a-console-application
/// </summary>
internal class AzureADAuthenticationMatcher : IStringMatcher
{
private const string BearerPrefix = "Bearer ";
private readonly string _audience;
@@ -24,8 +26,8 @@ namespace WireMock.Authentication
public AzureADAuthenticationMatcher(string tenant, string audience)
{
_audience = audience;
_stsDiscoveryEndpoint = string.Format(CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}/.well-known/openid-configuration", tenant);
_audience = Guard.NotNullOrEmpty(audience);
_stsDiscoveryEndpoint = string.Format(CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}/.well-known/openid-configuration", Guard.NotNullOrEmpty(tenant));
}
public string Name => nameof(AzureADAuthenticationMatcher);
@@ -36,13 +38,18 @@ namespace WireMock.Authentication
public AnyOf<string, StringPattern>[] GetPatterns()
{
return new AnyOf<string, StringPattern>[0];
return EmptyArray<AnyOf<string, StringPattern>>.Value;
}
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
public double IsMatch(string input)
public double IsMatch(string? input)
{
if (string.IsNullOrEmpty(input))
{
return MatchScores.Mismatch;
}
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase);
try
@@ -68,6 +75,5 @@ namespace WireMock.Authentication
return MatchScores.Mismatch;
}
}
}
}
#endif
@@ -2,10 +2,10 @@ using System;
using System.Text;
using WireMock.Matchers;
namespace WireMock.Authentication
namespace WireMock.Authentication;
internal class BasicAuthenticationMatcher : RegexMatcher
{
internal class BasicAuthenticationMatcher : RegexMatcher
{
public BasicAuthenticationMatcher(string username, string password) : base(BuildPattern(username, password))
{
}
@@ -16,5 +16,4 @@ namespace WireMock.Authentication
{
return "^(?i)BASIC " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password)) + "$";
}
}
}
@@ -0,0 +1,11 @@
// ReSharper disable once CheckNamespace
namespace System;
internal static class EmptyArray<T>
{
#if NET451 || NET452
public static readonly T[] Value = new T[0];
#else
public static readonly T[] Value = Array.Empty<T>();
#endif
}
+6 -8
View File
@@ -1,13 +1,12 @@
#if NETSTANDARD1_3
using System;
using System.Net;
#if NETSTANDARD1_3
namespace System.Net
// ReSharper disable once CheckNamespace
namespace System.Net;
internal class WebProxy : IWebProxy
{
internal class WebProxy : IWebProxy
{
private readonly string _proxy;
public ICredentials Credentials { get; set; }
public ICredentials? Credentials { get; set; }
public WebProxy(string proxy)
{
@@ -23,6 +22,5 @@ namespace System.Net
{
return true;
}
}
}
#endif
@@ -1,26 +1,24 @@
using System.Collections.Generic;
using System.Linq;
using AnyOfTypes;
using JetBrains.Annotations;
using WireMock.Models;
namespace WireMock.Extensions
namespace WireMock.Extensions;
internal static class AnyOfExtensions
{
internal static class AnyOfExtensions
{
public static string GetPattern([NotNull] this AnyOf<string, StringPattern> value)
public static string GetPattern(this AnyOf<string, StringPattern> value)
{
return value.IsFirst ? value.First : value.Second.Pattern;
}
public static AnyOf<string, StringPattern>[] ToAnyOfPatterns([NotNull] this IEnumerable<string> patterns)
public static AnyOf<string, StringPattern>[] ToAnyOfPatterns(this IEnumerable<string> patterns)
{
return patterns.Select(p => p.ToAnyOfPattern()).ToArray();
}
public static AnyOf<string, StringPattern> ToAnyOfPattern([CanBeNull] this string pattern)
public static AnyOf<string, StringPattern> ToAnyOfPattern(this string pattern)
{
return new AnyOf<string, StringPattern>(pattern);
}
}
}
@@ -1,21 +1,20 @@
using System.Net.Http;
using System.Net.Http;
using System.Net.Http.Headers;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Http
namespace WireMock.Http;
internal static class ByteArrayContentHelper
{
internal static class ByteArrayContentHelper
{
/// <summary>
/// Creates a ByteArrayContent object.
/// </summary>
/// <param name="content">The byte[] content (cannot be null)</param>
/// <param name="contentType">The ContentType (can be null)</param>
/// <returns>ByteArrayContent</returns>
internal static ByteArrayContent Create([NotNull] byte[] content, [CanBeNull] MediaTypeHeaderValue contentType)
internal static ByteArrayContent Create(byte[] content, MediaTypeHeaderValue? contentType)
{
Guard.NotNull(content, nameof(content));
Guard.NotNull(content);
var byteContent = new ByteArrayContent(content);
if (contentType != null)
@@ -26,5 +25,4 @@ namespace WireMock.Http
return byteContent;
}
}
}
@@ -1,17 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Linq;
namespace WireMock.Http
namespace WireMock.Http;
/// <summary>
/// Copied from https://raw.githubusercontent.com/dotnet/corefx/master/src/Common/src/System/Net/HttpKnownHeaderNames.cs
/// </summary>
internal static class HttpKnownHeaderNames
{
/// <summary>
/// Copied from https://raw.githubusercontent.com/dotnet/corefx/master/src/Common/src/System/Net/HttpKnownHeaderNames.cs
/// </summary>
internal static class HttpKnownHeaderNames
{
// https://docs.microsoft.com/en-us/dotnet/api/system.net.webheadercollection.isrestricted
private static readonly string[] RestrictedResponseHeaders =
{
@@ -118,5 +118,4 @@ namespace WireMock.Http
public const string XPoweredBy = "X-Powered-By";
public const string XRequestID = "X-Request-ID";
public const string XUACompatible = "X-UA-Compatible";
}
}
@@ -3,23 +3,22 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using JetBrains.Annotations;
using Newtonsoft.Json;
using WireMock.Types;
using Stef.Validation;
using WireMock.Types;
namespace WireMock.Http
namespace WireMock.Http;
internal static class HttpRequestMessageHelper
{
internal static class HttpRequestMessageHelper
internal static HttpRequestMessage Create(IRequestMessage requestMessage, string url)
{
internal static HttpRequestMessage Create([NotNull] IRequestMessage requestMessage, [NotNull] string url)
{
Guard.NotNull(requestMessage, nameof(requestMessage));
Guard.NotNullOrEmpty(url, nameof(url));
Guard.NotNull(requestMessage);
Guard.NotNullOrEmpty(url);
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
MediaTypeHeaderValue contentType = null;
MediaTypeHeaderValue? contentType = null;
if (requestMessage.Headers != null && requestMessage.Headers.ContainsKey(HttpKnownHeaderNames.ContentType))
{
var value = requestMessage.Headers[HttpKnownHeaderNames.ContentType].FirstOrDefault();
@@ -87,5 +86,4 @@ namespace WireMock.Http
return httpRequestMessage;
}
}
}
+6 -7
View File
@@ -1,10 +1,10 @@
namespace WireMock.Http
namespace WireMock.Http;
/// <summary>
/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
/// </summary>
internal static class HttpRequestMethods
{
/// <summary>
/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
/// </summary>
internal static class HttpRequestMethods
{
public const string CONNECT = "CONNECT";
public const string DELETE = "DELETE";
public const string GET = "GET";
@@ -14,5 +14,4 @@
public const string POST = "POST";
public const string PUT = "PUT";
public const string TRACE = "TRACE";
}
}
+6 -8
View File
@@ -1,25 +1,23 @@
using System.Net.Http;
using System.Net.Http;
using System.Net.Http.Headers;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Http
namespace WireMock.Http;
internal static class StringContentHelper
{
internal static class StringContentHelper
{
/// <summary>
/// Creates a StringContent object.
/// </summary>
/// <param name="content">The string content (cannot be null)</param>
/// <param name="contentType">The ContentType (can be null)</param>
/// <returns>StringContent</returns>
internal static StringContent Create([NotNull] string content, [CanBeNull] MediaTypeHeaderValue contentType)
internal static StringContent Create(string content, MediaTypeHeaderValue? contentType)
{
Guard.NotNull(content, nameof(content));
Guard.NotNull(content);
var stringContent = new StringContent(content);
stringContent.Headers.ContentType = contentType;
return stringContent;
}
}
}
+5 -7
View File
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Models;
using WireMock.Settings;
using WireMock.Transformers;
@@ -11,19 +11,18 @@ using WireMock.Transformers.Handlebars;
using WireMock.Transformers.Scriban;
using WireMock.Types;
using WireMock.Util;
using Stef.Validation;
namespace WireMock.Http
namespace WireMock.Http;
internal class WebhookSender
{
internal class WebhookSender
{
private const string ClientIp = "::1";
private readonly WireMockServerSettings _settings;
public WebhookSender(WireMockServerSettings settings)
{
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
_settings = Guard.NotNull(settings);
}
public Task<HttpResponseMessage> SendAsync(HttpClient client, IWebhookRequest request, IRequestMessage originalRequestMessage, IResponseMessage originalResponseMessage)
@@ -81,5 +80,4 @@ namespace WireMock.Http
// Call the URL
return client.SendAsync(httpRequestMessage);
}
}
}
@@ -2,10 +2,10 @@ using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace WireMock.HttpsCertificate
namespace WireMock.HttpsCertificate;
internal static class CertificateLoader
{
internal static class CertificateLoader
{
/// <summary>
/// Used by the WireMock.Net server
/// </summary>
@@ -101,5 +101,4 @@ namespace WireMock.HttpsCertificate
#endif
}
}
}
}
@@ -1,13 +1,13 @@
using System;
using System;
using System.Security.Cryptography.X509Certificates;
namespace WireMock.HttpsCertificate
namespace WireMock.HttpsCertificate;
/// <summary>
/// Only used for NetStandard 1.3
/// </summary>
internal static class PublicCertificateHelper
{
/// <summary>
/// Only used for NetStandard 1.3
/// </summary>
internal static class PublicCertificateHelper
{
// 1] Generate using https://www.pluralsight.com/blog/software-development/selfcert-create-a-self-signed-certificate-interactively-gui-or-programmatically-in-net
// 2] Converted to Base64
private const string Data = @"MIIQMgIBAzCCD+4GCSqGSIb3DQEHAaCCD98Egg/bMIIP1zCCCogGCSqGSIb3DQEHAaCCCnkEggp1
@@ -90,5 +90,4 @@ wTM1Z+CJZG9xAcf1zAVGl4ggYyYEFGBFyJ8VBwijS2zy1qwN1WYGtcWoAgIH0A==
byte[] data = Convert.FromBase64String(Data);
return new X509Certificate2(data);
}
}
}
+1 -1
View File
@@ -117,7 +117,7 @@ public interface IMapping
/// </summary>
/// <param name="requestMessage">The request message.</param>
/// <returns>The <see cref="ResponseMessage"/> including a new (optional) <see cref="IMapping"/>.</returns>
Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage);
Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage);
/// <summary>
/// Gets the RequestMatchResult based on the RequestMessage.
+9 -10
View File
@@ -1,13 +1,13 @@
using System;
using System;
using WireMock.Matchers.Request;
namespace WireMock.Logging
namespace WireMock.Logging;
/// <summary>
/// LogEntry
/// </summary>
public class LogEntry : ILogEntry
{
/// <summary>
/// LogEntry
/// </summary>
public class LogEntry : ILogEntry
{
/// <inheritdoc cref="ILogEntry.Guid" />
public Guid Guid { get; set; }
@@ -24,15 +24,14 @@ namespace WireMock.Logging
public Guid? MappingGuid { get; set; }
/// <inheritdoc cref="ILogEntry.MappingTitle" />
public string MappingTitle { get; set; }
public string? MappingTitle { get; set; }
/// <inheritdoc cref="ILogEntry.PartialMappingGuid" />
public Guid? PartialMappingGuid { get; set; }
/// <inheritdoc cref="ILogEntry.PartialMappingTitle" />
public string PartialMappingTitle { get; set; }
public string? PartialMappingTitle { get; set; }
/// <inheritdoc cref="ILogEntry.PartialMatchResult" />
public IRequestMatchResult PartialMatchResult { get; set; }
}
}
+1 -1
View File
@@ -116,7 +116,7 @@ public class Mapping : IMapping
}
/// <inheritdoc cref="IMapping.ProvideResponseAsync" />
public Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage)
public Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage)
{
return Provider.ProvideResponseAsync(requestMessage, Settings);
}
@@ -18,7 +18,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// </summary>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher([NotNull] AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
public ContentTypeMatcher(AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
{
}
@@ -28,7 +28,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
{
}
@@ -57,7 +57,7 @@ public class ContentTypeMatcher : WildcardMatcher
/// <inheritdoc cref="RegexMatcher.IsMatch"/>
public override double IsMatch(string? input)
{
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out MediaTypeHeaderValue contentType))
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out var contentType))
{
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
}
@@ -1,11 +1,10 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// CSharpCode / CS-Script Matcher
/// </summary>
/// <inheritdoc cref="IObjectMatcher"/>
/// <inheritdoc cref="IStringMatcher"/>
public interface ICSharpCodeMatcher : IObjectMatcher, IStringMatcher
{
/// <summary>
/// CSharpCode / CS-Script Matcher
/// </summary>
/// <inheritdoc cref="IObjectMatcher"/>
/// <inheritdoc cref="IStringMatcher"/>
public interface ICSharpCodeMatcher : IObjectMatcher, IStringMatcher
{
}
}
@@ -1,14 +1,13 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// IIgnoreCaseMatcher
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IIgnoreCaseMatcher : IMatcher
{
/// <summary>
/// IIgnoreCaseMatcher
/// </summary>
/// <inheritdoc cref="IMatcher"/>
public interface IIgnoreCaseMatcher : IMatcher
{
/// <summary>
/// Ignore the case from the pattern.
/// </summary>
bool IgnoreCase { get; }
}
}
+6 -7
View File
@@ -1,10 +1,10 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// IMatcher
/// </summary>
public interface IMatcher
{
/// <summary>
/// IMatcher
/// </summary>
public interface IMatcher
{
/// <summary>
/// Gets the name.
/// </summary>
@@ -19,5 +19,4 @@
/// Should this matcher throw an exception?
/// </summary>
bool ThrowException { get; }
}
}
+6 -7
View File
@@ -1,15 +1,14 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// IObjectMatcher
/// </summary>
public interface IObjectMatcher : IMatcher
{
/// <summary>
/// IObjectMatcher
/// </summary>
public interface IObjectMatcher : IMatcher
{
/// <summary>
/// Determines whether the specified input is match.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
double IsMatch(object? input);
}
}
+7 -8
View File
@@ -1,15 +1,14 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// IValueMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public interface IValueMatcher : IObjectMatcher
{
/// <summary>
/// IValueMatcher
/// </summary>
/// <seealso cref="IObjectMatcher" />
public interface IValueMatcher : IObjectMatcher
{
/// <summary>
/// Gets the value (can be a string or an object).
/// </summary>
/// <returns>Value</returns>
object Value { get; }
}
}
+6 -7
View File
@@ -6,13 +6,13 @@ using Stef.Validation;
using WireMock.Extensions;
using WireMock.Models;
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// http://jmespath.org/
/// </summary>
public class JmesPathMatcher : IStringMatcher, IObjectMatcher
{
/// <summary>
/// http://jmespath.org/
/// </summary>
public class JmesPathMatcher : IStringMatcher, IObjectMatcher
{
private readonly AnyOf<string, StringPattern>[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
@@ -116,5 +116,4 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JmesPathMatcher";
}
}
+1 -1
View File
@@ -119,7 +119,7 @@ public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
return tokenValue;
case string stringValue:
return JsonUtils.Parse(stringValue)!;
return JsonUtils.Parse(stringValue);
case IEnumerable enumerableValue:
return JArray.FromObject(enumerableValue);
+8 -4
View File
@@ -1,3 +1,4 @@
using System;
using System.Linq;
using System.Linq.Dynamic.Core;
using AnyOfTypes;
@@ -68,7 +69,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
public double IsMatch(string? input)
{
double match = MatchScores.Mismatch;
@@ -94,7 +95,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
public double IsMatch(object? input)
{
double match = MatchScores.Mismatch;
@@ -105,9 +106,12 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
value = valueAsJObject;
break;
default:
value = JObject.FromObject(input);
case { } valueAsObject:
value = JObject.FromObject(valueAsObject);
break;
default:
return MatchScores.Mismatch;
}
// Convert a single object to a Queryable JObject-list with 1 entry.
+6 -7
View File
@@ -1,10 +1,10 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
/// <summary>
/// MatchBehaviour
/// </summary>
public enum MatchBehaviour
{
/// <summary>
/// MatchBehaviour
/// </summary>
public enum MatchBehaviour
{
/// <summary>
/// Accept on match (default)
/// </summary>
@@ -14,5 +14,4 @@
/// Reject on match
/// </summary>
RejectOnMatch
}
}
@@ -1,7 +1,7 @@
namespace WireMock.Matchers
namespace WireMock.Matchers;
internal static class MatchBehaviourHelper
{
internal static class MatchBehaviourHelper
{
/// <summary>
/// Converts the specified match behaviour and match value to a new match value.
///
@@ -23,5 +23,4 @@
return match <= MatchScores.Tolerance ? MatchScores.Perfect : MatchScores.Mismatch;
}
}
}
@@ -1,10 +1,10 @@
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// CompositeMatcherType
/// </summary>
public enum CompositeMatcherType
{
/// <summary>
/// CompositeMatcherType
/// </summary>
public enum CompositeMatcherType
{
/// <summary>
/// And
/// </summary>
@@ -14,5 +14,4 @@
/// Or
/// </summary>
Or = 1
}
}
@@ -1,14 +1,14 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// RequestMatchResult
/// </summary>
public class RequestMatchResult : IRequestMatchResult
{
/// <summary>
/// RequestMatchResult
/// </summary>
public class RequestMatchResult : IRequestMatchResult
{
/// <inheritdoc cref="IRequestMatchResult.TotalScore" />
public double TotalScore => MatchDetails.Sum(md => md.Score);
@@ -53,5 +53,4 @@ namespace WireMock.Matchers.Request
// In case the score is equal, prefer the one with the most matchers.
return averageTotalScoreResult == 0 ? compareObj.TotalNumber.CompareTo(TotalNumber) : averageTotalScoreResult;
}
}
}
@@ -3,13 +3,13 @@ using System.Linq;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The composite request matcher.
/// </summary>
public abstract class RequestMessageCompositeMatcher : IRequestMatcher
{
/// <summary>
/// The composite request matcher.
/// </summary>
public abstract class RequestMessageCompositeMatcher : IRequestMatcher
{
private readonly CompositeMatcherType _type;
/// <summary>
@@ -48,5 +48,4 @@ namespace WireMock.Matchers.Request
return RequestMatchers.Max(requestMatcher => requestMatcher.GetMatchingScore(requestMessage, requestMatchResult));
}
}
}
@@ -4,14 +4,14 @@ using System.Linq;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The request cookie matcher.
/// </summary>
/// <inheritdoc cref="IRequestMatcher"/>
public class RequestMessageCookieMatcher : IRequestMatcher
{
/// <summary>
/// The request cookie matcher.
/// </summary>
/// <inheritdoc cref="IRequestMatcher"/>
public class RequestMessageCookieMatcher : IRequestMatcher
{
private readonly MatchBehaviour _matchBehaviour;
private readonly bool _ignoreCase;
@@ -125,5 +125,4 @@ namespace WireMock.Matchers.Request
string value = cookies[Name];
return Matchers.Max(m => m.IsMatch(value));
}
}
}
+2 -3
View File
@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
@@ -30,9 +29,9 @@ namespace WireMock.Owin
public bool IsStarted { get; private set; }
public List<string> Urls { get; } = new List<string>();
public List<string> Urls { get; } = new();
public List<int> Ports { get; } = new List<int>();
public List<int> Ports { get; } = new();
public Exception RunningException => _runningException;
@@ -71,7 +71,6 @@ namespace WireMock.Owin.Mappers
{
bytes = bytes.Take(bytes.Length / 2).Union(_randomizerBytes.Generate()).ToArray();
}
break;
default:
@@ -80,11 +79,10 @@ namespace WireMock.Owin.Mappers
}
var statusCodeType = responseMessage.StatusCode?.GetType();
switch (statusCodeType)
{
case Type typeAsIntOrEnum when typeAsIntOrEnum == typeof(int) || typeAsIntOrEnum == typeof(int?) || typeAsIntOrEnum.GetTypeInfo().IsEnum:
response.StatusCode = MapStatusCode((int)responseMessage.StatusCode);
response.StatusCode = MapStatusCode((int)responseMessage.StatusCode!);
break;
case Type typeAsString when typeAsString == typeof(string):
@@ -138,7 +136,7 @@ namespace WireMock.Owin.Mappers
return responseMessage.BodyData.BodyAsBytes;
case BodyType.File:
return _options.FileSystemHandler.ReadResponseBodyAsFile(responseMessage.BodyData.BodyAsFile);
return _options.FileSystemHandler?.ReadResponseBodyAsFile(responseMessage.BodyData.BodyAsFile);
}
return null;
@@ -2,11 +2,11 @@ namespace WireMock.Pact.Models.V2;
public class Interaction
{
public string Description { get; set; } = string.Empty;
public string? Description { get; set; }
public string ProviderState { get; set; }
public string? ProviderState { get; set; }
public PactRequest Request { get; set; } = new PactRequest();
public PactRequest Request { get; set; } = new();
public PactResponse Response { get; set; } = new PactResponse();
public PactResponse Response { get; set; } = new();
}
+7 -8
View File
@@ -1,14 +1,14 @@
using System;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Reflection;
namespace WireMock.Plugin
namespace WireMock.Plugin;
internal static class PluginLoader
{
internal static class PluginLoader
{
private static readonly ConcurrentDictionary<Type, Type> Assemblies = new ConcurrentDictionary<Type, Type>();
private static readonly ConcurrentDictionary<Type, Type> Assemblies = new();
public static T Load<T>(params object[] args) where T : class
{
@@ -16,7 +16,7 @@ namespace WireMock.Plugin
{
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll");
Type pluginType = null;
Type? pluginType = null;
foreach (var file in files)
{
try
@@ -49,9 +49,8 @@ namespace WireMock.Plugin
return (T)Activator.CreateInstance(foundType, args);
}
private static Type GetImplementationTypeByInterface<T>(Assembly assembly)
private static Type? GetImplementationTypeByInterface<T>(Assembly assembly)
{
return assembly.GetTypes().FirstOrDefault(t => typeof(T).IsAssignableFrom(t) && !t.GetTypeInfo().IsInterface);
}
}
}
@@ -77,7 +77,7 @@ internal class RegexExtended : Regex
/// <param name="pattern">Pattern to replace token for.</param>
private static string ReplaceGuidPattern(string pattern)
{
Guard.NotNull(pattern, nameof(pattern));
Guard.NotNull(pattern);
foreach (var tokenPattern in GuidTokenPatterns)
{
+2 -2
View File
@@ -47,10 +47,10 @@ public class RequestMessage : IRequestMessage
public string Method { get; }
/// <inheritdoc cref="IRequestMessage.Headers" />
public IDictionary<string, WireMockList<string>> Headers { get; }
public IDictionary<string, WireMockList<string>>? Headers { get; }
/// <inheritdoc cref="IRequestMessage.Cookies" />
public IDictionary<string, string> Cookies { get; }
public IDictionary<string, string>? Cookies { get; }
/// <inheritdoc cref="IRequestMessage.Query" />
public IDictionary<string, WireMockList<string>>? Query { get; }
@@ -1,10 +1,10 @@
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// Defines the BodyDestinationFormat
/// </summary>
public static class BodyDestinationFormat
{
/// <summary>
/// Defines the BodyDestinationFormat
/// </summary>
public static class BodyDestinationFormat
{
/// <summary>
/// Same as source (no conversion)
/// </summary>
@@ -24,5 +24,4 @@
/// Convert to Json object
/// </summary>
public const string Json = "Json";
}
}
@@ -2,13 +2,13 @@ using System;
using System.Text;
using System.Threading.Tasks;
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// The BodyResponseBuilder interface.
/// </summary>
public interface IBodyResponseBuilder : IFaultResponseBuilder
{
/// <summary>
/// The BodyResponseBuilder interface.
/// </summary>
public interface IBodyResponseBuilder : IFaultResponseBuilder
{
/// <summary>
/// WithBody : Create a ... response based on a string.
/// </summary>
@@ -69,5 +69,4 @@ namespace WireMock.ResponseBuilders
/// <param name="cache">Defines if this file is cached in memory or retrieved from disk every time the response is created.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyFromFile(string filename, bool cache = true);
}
}
@@ -3,25 +3,24 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.ResponseProviders;
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// The CallbackResponseBuilder interface.
/// </summary>
public interface ICallbackResponseBuilder : IResponseProvider
{
/// <summary>
/// The CallbackResponseBuilder interface.
/// </summary>
public interface ICallbackResponseBuilder : IResponseProvider
{
/// <summary>
/// The callback builder
/// </summary>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
[PublicAPI]
IResponseBuilder WithCallback([NotNull] Func<IRequestMessage, ResponseMessage> callbackHandler);
IResponseBuilder WithCallback(Func<IRequestMessage, ResponseMessage> callbackHandler);
/// <summary>
/// The async callback builder
/// </summary>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
[PublicAPI]
IResponseBuilder WithCallback([NotNull] Func<IRequestMessage, Task<ResponseMessage>> callbackHandler);
}
IResponseBuilder WithCallback(Func<IRequestMessage, Task<ResponseMessage>> callbackHandler);
}
@@ -1,12 +1,12 @@
using System;
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// The DelayResponseBuilder interface.
/// </summary>
public interface IDelayResponseBuilder : ICallbackResponseBuilder
{
/// <summary>
/// The DelayResponseBuilder interface.
/// </summary>
public interface IDelayResponseBuilder : ICallbackResponseBuilder
{
/// <summary>
/// The delay defined as a <see cref="TimeSpan"/>.
/// </summary>
@@ -28,5 +28,4 @@ namespace WireMock.ResponseBuilders
/// <param name="maximumMilliseconds">Maximum milliseconds to delay</param>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithRandomDelay(int minimumMilliseconds = 0, int maximumMilliseconds = 60_000);
}
}
@@ -1,18 +1,17 @@
using JetBrains.Annotations;
using JetBrains.Annotations;
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// The FaultRequestBuilder interface.
/// </summary>
public interface IFaultResponseBuilder : ITransformResponseBuilder
{
/// <summary>
/// The FaultRequestBuilder interface.
/// </summary>
public interface IFaultResponseBuilder : ITransformResponseBuilder
{
/// <summary>
/// WithBody : Create a fault response.
/// </summary>
/// <param name="faultType">The FaultType.</param>
/// <param name="percentage">The percentage when this fault should occur. When null, it's always a fault.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithFault(FaultType faultType, [CanBeNull] double? percentage = null);
}
IResponseBuilder WithFault(FaultType faultType, double? percentage = null);
}
@@ -1,4 +1,3 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using WireMock.Types;
@@ -1,20 +1,20 @@
using JetBrains.Annotations;
using WireMock.Settings;
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// The ProxyResponseBuilder interface.
/// </summary>
public interface IProxyResponseBuilder : IStatusCodeResponseBuilder
{
/// <summary>
/// The ProxyResponseBuilder interface.
/// </summary>
public interface IProxyResponseBuilder : IStatusCodeResponseBuilder
{
/// <summary>
/// WithProxy URL using Client X509Certificate2.
/// </summary>
/// <param name="proxyUrl">The proxy url.</param>
/// <param name="clientX509Certificate2ThumbprintOrSubjectName">The X509Certificate2 file to use for client authentication.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithProxy([NotNull] string proxyUrl, [CanBeNull] string clientX509Certificate2ThumbprintOrSubjectName = null);
IResponseBuilder WithProxy(string proxyUrl, string? clientX509Certificate2ThumbprintOrSubjectName = null);
/// <summary>
/// WithProxy using IProxyAndRecordSettings.
@@ -22,5 +22,4 @@ namespace WireMock.ResponseBuilders
/// <param name="settings">The IProxyAndRecordSettings.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithProxy([NotNull] ProxyAndRecordSettings settings);
}
}
@@ -1,9 +1,8 @@
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// The ResponseBuilder interface.
/// </summary>
public interface IResponseBuilder : IProxyResponseBuilder
{
/// <summary>
/// The ResponseBuilder interface.
/// </summary>
public interface IResponseBuilder : IProxyResponseBuilder
{
}
}
@@ -1,13 +1,13 @@
using System.Net;
using System.Net;
using WireMock.Settings;
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// The StatusCodeResponseBuilder interface.
/// </summary>
public interface IStatusCodeResponseBuilder : IHeadersResponseBuilder
{
/// <summary>
/// The StatusCodeResponseBuilder interface.
/// </summary>
public interface IStatusCodeResponseBuilder : IHeadersResponseBuilder
{
/// <summary>
/// The with status code.
/// By default all status codes are allowed, to change this behaviour, see <inheritdoc cref="WireMockServerSettings.AllowOnlyDefinedHttpStatusCodeInResponse"/>.
@@ -43,5 +43,4 @@ namespace WireMock.ResponseBuilders
/// </summary>
/// <returns>The <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithNotFound();
}
}
@@ -1,12 +1,12 @@
using WireMock.Types;
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// The TransformResponseBuilder interface.
/// </summary>
public interface ITransformResponseBuilder : IDelayResponseBuilder
{
/// <summary>
/// The TransformResponseBuilder interface.
/// </summary>
public interface ITransformResponseBuilder : IDelayResponseBuilder
{
/// <summary>
/// Use the Handlebars.Net ResponseMessage transformer.
/// </summary>
@@ -30,5 +30,4 @@ namespace WireMock.ResponseBuilders
/// The <see cref="IResponseBuilder"/>.
/// </returns>
IResponseBuilder WithTransformer(TransformerType transformerType = TransformerType.Handlebars, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.None);
}
}
@@ -1,20 +1,23 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Stef.Validation;
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
public partial class Response
{
public partial class Response
{
/// <summary>
/// A delegate to execute to generate the response.
/// </summary>
public Func<IRequestMessage, ResponseMessage> Callback { get; private set; }
[MemberNotNullWhen(true, nameof(WithCallbackUsed))]
public Func<IRequestMessage, ResponseMessage>? Callback { get; private set; }
/// <summary>
/// A delegate to execute to generate the response async.
/// </summary>
public Func<IRequestMessage, Task<ResponseMessage>> CallbackAsync { get; private set; }
[MemberNotNullWhen(true, nameof(WithCallbackUsed))]
public Func<IRequestMessage, Task<ResponseMessage>>? CallbackAsync { get; private set; }
/// <summary>
/// Defines if the method WithCallback(...) is used.
@@ -24,7 +27,7 @@ namespace WireMock.ResponseBuilders
/// <inheritdoc />
public IResponseBuilder WithCallback(Func<IRequestMessage, ResponseMessage> callbackHandler)
{
Guard.NotNull(callbackHandler, nameof(callbackHandler));
Guard.NotNull(callbackHandler);
return WithCallbackInternal(true, callbackHandler);
}
@@ -32,14 +35,14 @@ namespace WireMock.ResponseBuilders
/// <inheritdoc />
public IResponseBuilder WithCallback(Func<IRequestMessage, Task<ResponseMessage>> callbackHandler)
{
Guard.NotNull(callbackHandler, nameof(callbackHandler));
Guard.NotNull(callbackHandler);
return WithCallbackInternal(true, callbackHandler);
}
private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func<IRequestMessage, ResponseMessage> callbackHandler)
{
Guard.NotNull(callbackHandler, nameof(callbackHandler));
Guard.NotNull(callbackHandler);
WithCallbackUsed = withCallbackUsed;
Callback = callbackHandler;
@@ -49,12 +52,11 @@ namespace WireMock.ResponseBuilders
private IResponseBuilder WithCallbackInternal(bool withCallbackUsed, Func<IRequestMessage, Task<ResponseMessage>> callbackHandler)
{
Guard.NotNull(callbackHandler, nameof(callbackHandler));
Guard.NotNull(callbackHandler);
WithCallbackUsed = withCallbackUsed;
CallbackAsync = callbackHandler;
return this;
}
}
}
@@ -1,7 +1,7 @@
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
public partial class Response
{
public partial class Response
{
/// <inheritdoc cref="IFaultResponseBuilder.WithFault(FaultType, double?)"/>
public IResponseBuilder WithFault(FaultType faultType, double? percentage = null)
{
@@ -10,5 +10,4 @@
return this;
}
}
}
@@ -7,7 +7,7 @@ namespace WireMock.ResponseBuilders;
public partial class Response
{
private HttpClient _httpClientForProxy;
private HttpClient? _httpClientForProxy;
/// <summary>
/// The WebProxy settings.
+33 -34
View File
@@ -10,7 +10,6 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Proxy;
using WireMock.ResponseProviders;
using WireMock.Settings;
using WireMock.Transformers;
using WireMock.Transformers.Handlebars;
@@ -18,14 +17,14 @@ using WireMock.Transformers.Scriban;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.ResponseBuilders
namespace WireMock.ResponseBuilders;
/// <summary>
/// The Response.
/// </summary>
public partial class Response : IResponseBuilder
{
/// <summary>
/// The Response.
/// </summary>
public partial class Response : IResponseBuilder
{
private static readonly ThreadLocal<Random> Random = new ThreadLocal<Random>(() => new Random(DateTime.UtcNow.Millisecond));
private static readonly ThreadLocal<Random> Random = new(() => new Random(DateTime.UtcNow.Millisecond));
private TimeSpan? _delay;
@@ -48,7 +47,7 @@ namespace WireMock.ResponseBuilders
{
if (MinimumDelayMilliseconds != null && MaximumDelayMilliseconds != null)
{
return TimeSpan.FromMilliseconds(Random.Value.Next(MinimumDelayMilliseconds.Value, MaximumDelayMilliseconds.Value));
return TimeSpan.FromMilliseconds(Random.Value!.Next(MinimumDelayMilliseconds.Value, MaximumDelayMilliseconds.Value));
}
return _delay;
@@ -88,7 +87,7 @@ namespace WireMock.ResponseBuilders
/// <param name="responseMessage">ResponseMessage</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
[PublicAPI]
public static IResponseBuilder Create([CanBeNull] ResponseMessage responseMessage = null)
public static IResponseBuilder Create(ResponseMessage? responseMessage = null)
{
var message = responseMessage ?? new ResponseMessage();
return new Response(message);
@@ -100,9 +99,9 @@ namespace WireMock.ResponseBuilders
/// <param name="func">The callback function.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
[PublicAPI]
public static IResponseBuilder Create([NotNull] Func<ResponseMessage> func)
public static IResponseBuilder Create(Func<ResponseMessage> func)
{
Guard.NotNull(func, nameof(func));
Guard.NotNull(func);
return new Response(func());
}
@@ -164,7 +163,7 @@ namespace WireMock.ResponseBuilders
/// <inheritdoc cref="IHeadersResponseBuilder.WithHeader(string, string[])"/>
public IResponseBuilder WithHeader(string name, params string[] values)
{
Guard.NotNull(name, nameof(name));
Guard.NotNull(name);
ResponseMessage.AddHeader(name, values);
return this;
@@ -173,7 +172,7 @@ namespace WireMock.ResponseBuilders
/// <inheritdoc cref="IHeadersResponseBuilder.WithHeaders(IDictionary{string, string})"/>
public IResponseBuilder WithHeaders(IDictionary<string, string> headers)
{
Guard.NotNull(headers, nameof(headers));
Guard.NotNull(headers);
ResponseMessage.Headers = headers.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
return this;
@@ -182,7 +181,7 @@ namespace WireMock.ResponseBuilders
/// <inheritdoc cref="IHeadersResponseBuilder.WithHeaders(IDictionary{string, string[]})"/>
public IResponseBuilder WithHeaders(IDictionary<string, string[]> headers)
{
Guard.NotNull(headers, nameof(headers));
Guard.NotNull(headers);
ResponseMessage.Headers = headers.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
return this;
@@ -191,12 +190,14 @@ namespace WireMock.ResponseBuilders
/// <inheritdoc cref="IHeadersResponseBuilder.WithHeaders(IDictionary{string, WireMockList{string}})"/>
public IResponseBuilder WithHeaders(IDictionary<string, WireMockList<string>> headers)
{
Guard.NotNull(headers);
ResponseMessage.Headers = headers;
return this;
}
/// <inheritdoc />
public IResponseBuilder WithBody(Func<IRequestMessage, string> bodyFactory, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null)
public IResponseBuilder WithBody(Func<IRequestMessage, string> bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null)
{
Guard.NotNull(bodyFactory, nameof(bodyFactory));
@@ -212,7 +213,7 @@ namespace WireMock.ResponseBuilders
}
/// <inheritdoc />
public IResponseBuilder WithBody(Func<IRequestMessage, Task<string>> bodyFactory, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null)
public IResponseBuilder WithBody(Func<IRequestMessage, Task<string>> bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null)
{
Guard.NotNull(bodyFactory, nameof(bodyFactory));
@@ -227,10 +228,10 @@ namespace WireMock.ResponseBuilders
});
}
/// <inheritdoc cref="IBodyResponseBuilder.WithBody(byte[], string, Encoding)"/>
public IResponseBuilder WithBody(byte[] body, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null)
/// <inheritdoc />
public IResponseBuilder WithBody(byte[] body, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null)
{
Guard.NotNull(body, nameof(body));
Guard.NotNull(body);
ResponseMessage.BodyDestination = destination;
ResponseMessage.BodyData = new BodyData();
@@ -256,7 +257,7 @@ namespace WireMock.ResponseBuilders
/// <inheritdoc cref="IBodyResponseBuilder.WithBodyFromFile"/>
public IResponseBuilder WithBodyFromFile(string filename, bool cache = true)
{
Guard.NotNull(filename, nameof(filename));
Guard.NotNull(filename);
ResponseMessage.BodyData = new BodyData
{
@@ -276,15 +277,14 @@ namespace WireMock.ResponseBuilders
return this;
}
/// <inheritdoc cref="IBodyResponseBuilder.WithBody(string, string, Encoding)"/>
public IResponseBuilder WithBody(string body, string destination = BodyDestinationFormat.SameAsSource, Encoding encoding = null)
/// <inheritdoc />
public IResponseBuilder WithBody(string body, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null)
{
Guard.NotNull(body, nameof(body));
Guard.NotNull(body);
encoding = encoding ?? Encoding.UTF8;
encoding ??= Encoding.UTF8;
ResponseMessage.BodyDestination = destination;
ResponseMessage.BodyData = new BodyData
{
Encoding = encoding
@@ -312,9 +312,9 @@ namespace WireMock.ResponseBuilders
}
/// <inheritdoc cref="IBodyResponseBuilder.WithBodyAsJson(object, Encoding, bool?)"/>
public IResponseBuilder WithBodyAsJson(object body, Encoding encoding = null, bool? indented = null)
public IResponseBuilder WithBodyAsJson(object body, Encoding? encoding = null, bool? indented = null)
{
Guard.NotNull(body, nameof(body));
Guard.NotNull(body);
ResponseMessage.BodyDestination = null;
ResponseMessage.BodyData = new BodyData
@@ -384,10 +384,10 @@ namespace WireMock.ResponseBuilders
}
/// <inheritdoc />
public async Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings)
public async Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings)
{
Guard.NotNull(requestMessage, nameof(requestMessage));
Guard.NotNull(settings, nameof(settings));
Guard.NotNull(requestMessage);
Guard.NotNull(settings);
if (Delay != null)
{
@@ -431,7 +431,7 @@ namespace WireMock.ResponseBuilders
}
else
{
responseMessage = await CallbackAsync(requestMessage).ConfigureAwait(false);
responseMessage = await CallbackAsync!(requestMessage).ConfigureAwait(false);
}
// Copy StatusCode from ResponseMessage (if defined)
@@ -472,10 +472,9 @@ namespace WireMock.ResponseBuilders
if (!UseTransformer && ResponseMessage.BodyData?.BodyAsFileIsCached == true)
{
ResponseMessage.BodyData.BodyAsBytes = settings.FileSystemHandler.ReadResponseBodyAsFile(responseMessage.BodyData.BodyAsFile);
ResponseMessage.BodyData.BodyAsBytes = settings.FileSystemHandler.ReadResponseBodyAsFile(responseMessage.BodyData!.BodyAsFile);
}
return (responseMessage, null);
}
}
}
+13 -12
View File
@@ -7,24 +7,24 @@ using WireMock.Types;
using WireMock.Util;
using Stef.Validation;
namespace WireMock
namespace WireMock;
/// <summary>
/// The ResponseMessage.
/// </summary>
public class ResponseMessage : IResponseMessage
{
/// <summary>
/// The ResponseMessage.
/// </summary>
public class ResponseMessage : IResponseMessage
{
/// <inheritdoc cref="IResponseMessage.Headers" />
public IDictionary<string, WireMockList<string>>? Headers { get; set; } = new Dictionary<string, WireMockList<string>>();
/// <inheritdoc cref="IResponseMessage.StatusCode" />
public object StatusCode { get; set; }
public object? StatusCode { get; set; }
/// <inheritdoc cref="IResponseMessage.BodyOriginal" />
public string BodyOriginal { get; set; }
public string? BodyOriginal { get; set; }
/// <inheritdoc cref="IResponseMessage.BodyDestination" />
public string BodyDestination { get; set; }
public string? BodyDestination { get; set; }
/// <inheritdoc cref="IResponseMessage.BodyData" />
public IBodyData? BodyData { get; set; }
@@ -38,19 +38,20 @@ namespace WireMock
/// <inheritdoc cref="IResponseMessage.AddHeader(string, string)" />
public void AddHeader(string name, string value)
{
Headers ??= new Dictionary<string, WireMockList<string>>();
Headers.Add(name, new WireMockList<string>(value));
}
/// <inheritdoc cref="IResponseMessage.AddHeader(string, string[])" />
public void AddHeader(string name, params string[] values)
{
Guard.NotNullOrEmpty(values, nameof(values));
Guard.NotNullOrEmpty(values);
var newHeaderValues = Headers.TryGetValue(name, out WireMockList<string> existingValues)
Headers ??= new Dictionary<string, WireMockList<string>>();
var newHeaderValues = Headers.TryGetValue(name, out WireMockList<string>? existingValues)
? values.Union(existingValues).ToArray()
: values;
Headers[name] = new WireMockList<string>(newHeaderValues);
}
}
}
@@ -2,10 +2,10 @@ using System;
using System.Threading.Tasks;
using WireMock.Settings;
namespace WireMock.ResponseProviders
namespace WireMock.ResponseProviders;
internal class DynamicAsyncResponseProvider : IResponseProvider
{
internal class DynamicAsyncResponseProvider : IResponseProvider
{
private readonly Func<IRequestMessage, Task<IResponseMessage>> _responseMessageFunc;
public DynamicAsyncResponseProvider(Func<IRequestMessage, Task<IResponseMessage>> responseMessageFunc)
@@ -13,9 +13,8 @@ namespace WireMock.ResponseProviders
_responseMessageFunc = responseMessageFunc;
}
public async Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings)
public async Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings)
{
return (await _responseMessageFunc(requestMessage).ConfigureAwait(false), null);
}
}
}
@@ -2,10 +2,10 @@ using System;
using System.Threading.Tasks;
using WireMock.Settings;
namespace WireMock.ResponseProviders
namespace WireMock.ResponseProviders;
internal class DynamicResponseProvider : IResponseProvider
{
internal class DynamicResponseProvider : IResponseProvider
{
private readonly Func<IRequestMessage, IResponseMessage> _responseMessageFunc;
public DynamicResponseProvider(Func<IRequestMessage, IResponseMessage> responseMessageFunc)
@@ -13,10 +13,9 @@ namespace WireMock.ResponseProviders
_responseMessageFunc = responseMessageFunc;
}
public Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings)
public Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings)
{
(IResponseMessage responseMessage, IMapping mapping) result = (_responseMessageFunc(requestMessage), null);
(IResponseMessage responseMessage, IMapping? mapping) result = (_responseMessageFunc(requestMessage), null);
return Task.FromResult(result);
}
}
}
@@ -1,22 +1,20 @@
// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License.
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Settings;
namespace WireMock.ResponseProviders
namespace WireMock.ResponseProviders;
/// <summary>
/// The Response Provider interface.
/// </summary>
public interface IResponseProvider
{
/// <summary>
/// The Response Provider interface.
/// </summary>
public interface IResponseProvider
{
/// <summary>
/// The provide response.
/// </summary>
/// <param name="requestMessage">The request.</param>
/// <param name="settings">The WireMockServerSettings.</param>
/// <returns>The <see cref="ResponseMessage"/> including a new (optional) <see cref="IMapping"/>.</returns>
Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync([NotNull] IRequestMessage requestMessage, [NotNull] WireMockServerSettings settings);
}
Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings);
}
@@ -2,10 +2,10 @@ using System;
using System.Threading.Tasks;
using WireMock.Settings;
namespace WireMock.ResponseProviders
namespace WireMock.ResponseProviders;
internal class ProxyAsyncResponseProvider : IResponseProvider
{
internal class ProxyAsyncResponseProvider : IResponseProvider
{
private readonly Func<IRequestMessage, WireMockServerSettings, Task<IResponseMessage>> _responseMessageFunc;
private readonly WireMockServerSettings _settings;
@@ -15,9 +15,8 @@ namespace WireMock.ResponseProviders
_settings = settings;
}
public async Task<(IResponseMessage Message, IMapping Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings)
public async Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage, WireMockServerSettings settings)
{
return (await _responseMessageFunc(requestMessage, _settings).ConfigureAwait(false), null);
}
}
}
@@ -140,7 +140,7 @@ internal static class LogEntryMapper
MatchDetails = matchResult.MatchDetails.Select(md => new
{
Name = md.MatcherType.Name.Replace("RequestMessage", string.Empty),
Score = md.Score
md.Score
} as object).ToList()
};
}
@@ -6,6 +6,7 @@ using Stef.Validation;
using WireMock.Admin.Mappings;
using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.Models;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Settings;
@@ -116,9 +117,10 @@ internal class MappingConverter
mappingModel.Response.Delay = (int?)(response.Delay == Timeout.InfiniteTimeSpan ? TimeSpan.MaxValue.TotalMilliseconds : response.Delay?.TotalMilliseconds);
}
if (mapping.Webhooks?.Length == 1)
var nonNullableWebHooks = mapping.Webhooks?.Where(wh => wh != null).ToArray() ?? new IWebhook[0];
if (nonNullableWebHooks.Length == 1)
{
mappingModel.Webhook = WebhookMapper.Map(mapping.Webhooks[0]);
mappingModel.Webhook = WebhookMapper.Map(nonNullableWebHooks[0]);
}
else if (mapping.Webhooks?.Length > 1)
{
@@ -209,7 +211,7 @@ internal class MappingConverter
break;
}
if (response.ResponseMessage.BodyData.Encoding != null && response.ResponseMessage.BodyData.Encoding.WebName != "utf-8")
if (response.ResponseMessage.BodyData?.Encoding != null && response.ResponseMessage.BodyData.Encoding.WebName != "utf-8")
{
mappingModel.Response.BodyEncoding = new EncodingModel
{
@@ -22,10 +22,7 @@ internal class MappingToFileSaver
public void SaveMappingToFile(IMapping mapping, string? folder = null)
{
if (folder == null)
{
folder = _settings.FileSystemHandler.GetMappingFolder();
}
folder ??= _settings.FileSystemHandler.GetMappingFolder();
if (!_settings.FileSystemHandler.FolderExists(folder))
{
@@ -208,7 +208,7 @@ internal class MatcherMapper
return patternAsStringArray.ToAnyOfPatterns();
}
if (matcher.Patterns?.OfType<string>() is IEnumerable<string> patternsAsStringArray)
if (matcher.Patterns?.OfType<string>() is { } patternsAsStringArray)
{
return patternsAsStringArray.ToAnyOfPatterns();
}
+25 -9
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DevLab.JmesPath.Interop;
using WireMock.Admin.Mappings;
using WireMock.Extensions;
using WireMock.Matchers;
@@ -76,10 +77,25 @@ internal static class PactMapper
{
Status = MapStatusCode(response.StatusCode),
Headers = MapResponseHeaders(response.Headers),
Body = response.BodyAsJson
Body = MapBody(response)
};
}
private static object? MapBody(ResponseModel? response)
{
if (response?.BodyAsJson != null)
{
return response.BodyAsJson;
}
if (response?.Body != null) // In case the body is a string, try to deserialize into object, else just return the string
{
return JsonUtils.TryDeserializeObject<object?>(response.Body) ?? response.Body;
}
return null;
}
private static int MapStatusCode(object? statusCode)
{
if (statusCode is string statusCodeAsString)
@@ -138,13 +154,13 @@ internal static class PactMapper
return jsonMatcher?.Pattern;
}
private static string GetPatternAsStringFromMatchers(MatcherModel[]? matchers, string defaultValue)
{
if (matchers != null && matchers.Any() && matchers[0].Pattern is string patternAsString)
{
return patternAsString;
}
//private static string GetPatternAsStringFromMatchers(MatcherModel[]? matchers, string defaultValue)
//{
// if (matchers != null && matchers.Any() && matchers[0].Pattern is string patternAsString)
// {
// return patternAsString;
// }
return defaultValue;
}
// return defaultValue;
//}
}
@@ -1,16 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Stef.Validation;
using WireMock.Admin.Mappings;
using WireMock.Http;
using WireMock.Models;
using WireMock.Types;
using WireMock.Util;
namespace WireMock.Serialization
namespace WireMock.Serialization;
internal static class WebhookMapper
{
internal static class WebhookMapper
{
public static IWebhook Map(WebhookModel model)
{
var webhook = new Webhook
@@ -40,8 +41,8 @@ namespace WireMock.Serialization
webhook.Request.TransformerReplaceNodeOptions = option;
}
IEnumerable<string> contentTypeHeader = null;
if (webhook.Request.Headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)))
IEnumerable<string>? contentTypeHeader = null;
if (webhook.Request.Headers != null && webhook.Request.Headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)))
{
contentTypeHeader = webhook.Request.Headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)).Value;
}
@@ -70,10 +71,7 @@ namespace WireMock.Serialization
public static WebhookModel Map(IWebhook webhook)
{
if (webhook?.Request == null)
{
return null;
}
Guard.NotNull(webhook);
var model = new WebhookModel
{
@@ -108,5 +106,4 @@ namespace WireMock.Serialization
return model;
}
}
}
+28 -14
View File
@@ -292,7 +292,7 @@ public partial class WireMockServer
private IResponseMessage SettingsUpdate(IRequestMessage requestMessage)
{
var settings = DeserializeObject<SettingsModel>(requestMessage)!;
var settings = DeserializeObject<SettingsModel>(requestMessage);
// _settings
_settings.AllowBodyForAllHttpMethods = settings.AllowBodyForAllHttpMethods;
@@ -571,7 +571,7 @@ public partial class WireMockServer
{
var requestModel = DeserializeObject<RequestModel>(requestMessage);
var request = (Request)InitRequestBuilder(requestModel, false);
var request = (Request)InitRequestBuilder(requestModel, false)!;
var dict = new Dictionary<ILogEntry, RequestMatchResult>();
foreach (var logEntry in LogEntries.Where(le => !le.RequestMessage.Path.StartsWith("/__admin/")))
@@ -625,6 +625,23 @@ public partial class WireMockServer
_settings.FileSystemHandler.WriteFile(folder, filenameUpdated, bytes);
}
/// <summary>
/// Save the mappings as a Pact Json file V2.
/// </summary>
/// <param name="stream">The (file) stream.</param>
[PublicAPI]
public void SavePact(Stream stream)
{
var (_, bytes) = PactMapper.ToPact(this);
using var writer = new BinaryWriter(stream);
writer.Write(bytes);
if (stream.CanSeek)
{
stream.Seek(0, SeekOrigin.Begin);
}
}
/// <summary>
/// This stores details about the consumer of the interaction.
/// </summary>
@@ -714,31 +731,28 @@ public partial class WireMockServer
};
}
private static T? DeserializeObject<T>(IRequestMessage requestMessage)
private static T DeserializeObject<T>(IRequestMessage requestMessage) where T : new()
{
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.String)
return requestMessage.BodyData?.DetectedBodyType switch
{
return JsonUtils.DeserializeObject<T>(requestMessage.BodyData.BodyAsString);
}
BodyType.String => JsonUtils.DeserializeObject<T>(requestMessage.BodyData.BodyAsString),
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
{
return ((JObject)requestMessage.BodyData.BodyAsJson).ToObject<T>();
}
BodyType.Json when requestMessage.BodyData?.BodyAsJson != null => ((JObject)requestMessage.BodyData.BodyAsJson).ToObject<T>()!,
return default(T);
_ => throw new NotSupportedException()
};
}
private static T[] DeserializeRequestMessageToArray<T>(IRequestMessage requestMessage)
{
if (requestMessage.BodyData?.DetectedBodyType == BodyType.Json)
if (requestMessage.BodyData?.DetectedBodyType == BodyType.Json && requestMessage.BodyData.BodyAsJson != null)
{
var bodyAsJson = requestMessage.BodyData.BodyAsJson;
return DeserializeObjectToArray<T>(bodyAsJson);
}
return default(T[]);
throw new NotSupportedException();
}
private static T[] DeserializeJsonToArray<T>(string value)
@@ -754,6 +768,6 @@ public partial class WireMockServer
}
var singleResult = ((JObject)value).ToObject<T>();
return new[] { singleResult };
return new[] { singleResult! };
}
}
@@ -275,7 +275,7 @@ public partial class WireMockServer
}
else
{
var headers = JsonUtils.ParseJTokenToObject<string[]>(entry.Value) ?? new string[0];
var headers = JsonUtils.ParseJTokenToObject<string[]>(entry.Value);
responseBuilder.WithHeader(entry.Key, headers);
}
}
@@ -2,18 +2,18 @@ using System;
using System.Collections.Generic;
using System.Linq;
namespace WireMock.Settings
namespace WireMock.Settings;
// Based on http://blog.gauffin.org/2014/12/simple-command-line-parser/
internal class SimpleCommandLineParser
{
// Based on http://blog.gauffin.org/2014/12/simple-command-line-parser/
internal class SimpleCommandLineParser
{
private const string Sigil = "--";
private IDictionary<string, string[]> Arguments { get; } = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
public void Parse(string[] arguments)
{
string currentName = null;
string currentName = string.Empty;
var values = new List<string>();
@@ -51,21 +51,31 @@ namespace WireMock.Settings
return Arguments.ContainsKey(name);
}
public string[] GetValues(string name, string[] defaultValue = null)
public string[] GetValues(string name, string[] defaultValue)
{
return Contains(name) ? Arguments[name] : defaultValue;
}
public T GetValue<T>(string name, Func<string[], T> func, T defaultValue = default(T))
public string[]? GetValues(string name)
{
return Contains(name) ? Arguments[name] : default;
}
public T GetValue<T>(string name, Func<string[], T> func, T defaultValue)
{
return Contains(name) ? func(Arguments[name]) : defaultValue;
}
public T? GetValue<T>(string name, Func<string[], T> func)
{
return Contains(name) ? func(Arguments[name]) : default;
}
public bool GetBoolValue(string name, bool defaultValue = false)
{
return GetValue(name, values =>
{
string value = values.FirstOrDefault();
var value = values.FirstOrDefault();
return !string.IsNullOrEmpty(value) ? bool.Parse(value) : defaultValue;
}, defaultValue);
}
@@ -79,14 +89,18 @@ namespace WireMock.Settings
{
return GetValue(name, values =>
{
string value = values.FirstOrDefault();
var value = values.FirstOrDefault();
return !string.IsNullOrEmpty(value) ? int.Parse(value) : defaultValue;
}, defaultValue);
}
public string GetStringValue(string name, string defaultValue = null)
public string GetStringValue(string name, string defaultValue)
{
return GetValue(name, values => values.FirstOrDefault() ?? defaultValue, defaultValue);
}
public string? GetStringValue(string name)
{
return GetValue(name, values => values.FirstOrDefault());
}
}
+6 -7
View File
@@ -1,9 +1,8 @@
namespace WireMock.Settings
namespace WireMock.Settings;
/// <summary>
/// WebhookSettings
/// </summary>
public class WebhookSettings : HttpClientSettings
{
/// <summary>
/// WebhookSettings
/// </summary>
public class WebhookSettings : HttpClientSettings
{
}
}
@@ -251,5 +251,11 @@ namespace WireMock.Settings
/// </summary>
[PublicAPI, JsonIgnore]
public IDictionary<string, Func<MatcherModel, IMatcher>>? CustomMatcherMappings { get; set; }
/// <summary>
/// The <see cref="JsonSerializerSettings"/> used when the a JSON response is generated.
/// </summary>
[PublicAPI, JsonIgnore]
public JsonSerializerSettings? JsonSerializerSettings { get; set; }
}
}
@@ -1,16 +1,17 @@
using System;
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using Stef.Validation;
using WireMock.Logging;
using WireMock.Types;
namespace WireMock.Settings
namespace WireMock.Settings;
/// <summary>
/// A static helper class to parse commandline arguments into WireMockServerSettings.
/// </summary>
public static class WireMockServerSettingsParser
{
/// <summary>
/// A static helper class to parse commandline arguments into WireMockServerSettings.
/// </summary>
public static class WireMockServerSettingsParser
{
/// <summary>
/// Parse commandline arguments into WireMockServerSettings.
/// </summary>
@@ -18,7 +19,7 @@ namespace WireMock.Settings
/// <param name="logger">The logger (optional, can be null)</param>
/// <param name="settings">The parsed settings</param>
[PublicAPI]
public static bool TryParseArguments([NotNull] string[] args, out WireMockServerSettings settings, [CanBeNull] IWireMockLogger logger = null)
public static bool TryParseArguments(string[] args, [NotNullWhen(true)] out WireMockServerSettings? settings, IWireMockLogger? logger = null)
{
Guard.HasNoNulls(args, nameof(args));
@@ -82,7 +83,7 @@ namespace WireMock.Settings
settings.Urls = parser.GetValues("Urls", new[] { "http://*:9091/" });
}
string proxyUrl = parser.GetStringValue("ProxyURL") ?? parser.GetStringValue("ProxyUrl");
var proxyUrl = parser.GetStringValue("ProxyURL") ?? parser.GetStringValue("ProxyUrl");
if (!string.IsNullOrEmpty(proxyUrl))
{
settings.ProxyAndRecordSettings = new ProxyAndRecordSettings
@@ -93,12 +94,12 @@ namespace WireMock.Settings
ExcludedHeaders = parser.GetValues("ExcludedHeaders"),
// PreferProxyMapping = parser.GetBoolValue(nameof(ProxyAndRecordSettings.PreferProxyMapping)),
SaveMapping = parser.GetBoolValue("SaveMapping"),
SaveMappingForStatusCodePattern = parser.GetStringValue("SaveMappingForStatusCodePattern"),
SaveMappingForStatusCodePattern = parser.GetStringValue("SaveMappingForStatusCodePattern", "*"),
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
Url = proxyUrl
};
string proxyAddress = parser.GetStringValue("WebProxyAddress");
string? proxyAddress = parser.GetStringValue("WebProxyAddress");
if (!string.IsNullOrEmpty(proxyAddress))
{
settings.ProxyAndRecordSettings.WebProxySettings = new WebProxySettings
@@ -125,5 +126,4 @@ namespace WireMock.Settings
return true;
}
}
}
@@ -17,7 +17,7 @@ namespace WireMock.Util
private const int DefaultWatchInterval = 100;
// This Dictionary keeps the track of when an event occurred last for a particular file
private ConcurrentDictionary<string, DateTime> _lastFileEvent;
private ConcurrentDictionary<string, DateTime> _lastFileEvent = new();
// Watch Interval in Milliseconds
private int _interval;
@@ -58,7 +58,7 @@ namespace WireMock.Util
/// <param name="interval">The interval.</param>
public EnhancedFileSystemWatcher(int interval = DefaultWatchInterval)
{
Guard.Condition(interval, i => i >= 0, nameof(interval));
Guard.Condition(interval, i => i >= 0);
InitializeMembers(interval);
}
@@ -68,10 +68,10 @@ namespace WireMock.Util
/// </summary>
/// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</param>
/// <param name="interval">The interval.</param>
public EnhancedFileSystemWatcher([NotNull] string path, int interval = DefaultWatchInterval) : base(path)
public EnhancedFileSystemWatcher(string path, int interval = DefaultWatchInterval) : base(path)
{
Guard.NotNullOrEmpty(path, nameof(path));
Guard.Condition(interval, i => i >= 0, nameof(interval));
Guard.NotNullOrEmpty(path);
Guard.Condition(interval, i => i >= 0);
InitializeMembers(interval);
}
@@ -82,11 +82,11 @@ namespace WireMock.Util
/// <param name="path">The directory to monitor, in standard or Universal Naming Convention (UNC) notation.</param>
/// <param name="filter">The type of files to watch. For example, "*.txt" watches for changes to all text files.</param>
/// <param name="interval">The interval.</param>
public EnhancedFileSystemWatcher([NotNull] string path, [NotNull] string filter, int interval = DefaultWatchInterval) : base(path, filter)
public EnhancedFileSystemWatcher(string path, string filter, int interval = DefaultWatchInterval) : base(path, filter)
{
Guard.NotNullOrEmpty(path, nameof(path));
Guard.NotNullOrEmpty(filter, nameof(filter));
Guard.Condition(interval, i => i >= 0, nameof(interval));
Guard.NotNullOrEmpty(path);
Guard.NotNullOrEmpty(filter);
Guard.Condition(interval, i => i >= 0);
InitializeMembers(interval);
}
@@ -100,22 +100,22 @@ namespace WireMock.Util
/// <summary>
/// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is changed.
/// </summary>
public new event FileSystemEventHandler Changed;
public new event FileSystemEventHandler? Changed;
/// <summary>
/// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is created.
/// </summary>
public new event FileSystemEventHandler Created;
public new event FileSystemEventHandler? Created;
/// <summary>
/// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is deleted.
/// </summary>
public new event FileSystemEventHandler Deleted;
public new event FileSystemEventHandler? Deleted;
/// <summary>
/// Occurs when a file or directory in the specified <see cref="P:System.IO.FileSystemWatcher.Path" /> is renamed.
/// </summary>
public new event RenamedEventHandler Renamed;
public new event RenamedEventHandler? Renamed;
#endregion
#region Protected Methods to raise the Events for this class
@@ -16,7 +16,7 @@ internal static class HttpStatusRangeParser
/// <param name="pattern">The pattern. (Can be null, in that case it's allowed.)</param>
/// <param name="httpStatusCode">The value.</param>
/// <exception cref="ArgumentException"><paramref name="pattern"/> is invalid.</exception>
public static bool IsMatch(string pattern, object httpStatusCode)
public static bool IsMatch(string pattern, object? httpStatusCode)
{
switch (httpStatusCode)
{
+27 -9
View File
@@ -87,9 +87,9 @@ internal static class JsonUtils
/// </summary>
/// <param name="json">A System.String that contains JSON.</param>
/// <returns>A Newtonsoft.Json.Linq.JToken populated from the string that contains JSON.</returns>
public static JToken? Parse(string json)
public static JToken Parse(string json)
{
return JsonConvert.DeserializeObject<JToken>(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone);
return JsonConvert.DeserializeObject<JToken>(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone)!;
}
/// <summary>
@@ -98,9 +98,9 @@ internal static class JsonUtils
/// </summary>
/// <param name="json">A System.String that contains JSON.</param>
/// <returns>The deserialized object from the JSON string.</returns>
public static object? DeserializeObject(string json)
public static object DeserializeObject(string json)
{
return JsonConvert.DeserializeObject(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone);
return JsonConvert.DeserializeObject(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone)!;
}
/// <summary>
@@ -109,17 +109,35 @@ internal static class JsonUtils
/// </summary>
/// <param name="json">A System.String that contains JSON.</param>
/// <returns>The deserialized object from the JSON string.</returns>
public static T? DeserializeObject<T>(string json)
public static T DeserializeObject<T>(string json)
{
return JsonConvert.DeserializeObject<T>(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone);
return JsonConvert.DeserializeObject<T>(json, JsonSerializationConstants.JsonDeserializerSettingsWithDateParsingNone)!;
}
public static T? ParseJTokenToObject<T>(object value)
public static T? TryDeserializeObject<T>(string json)
{
try
{
return JsonConvert.DeserializeObject<T>(json);
}
catch
{
return default;
}
}
public static T ParseJTokenToObject<T>(object? value)
{
if (value != null && value.GetType() == typeof(T))
{
return (T)value;
}
return value switch
{
JToken tokenValue => tokenValue.ToObject<T>(),
_ => default
JToken tokenValue => tokenValue.ToObject<T>()!,
_ => throw new NotSupportedException($"Unable to convert value to {typeof(T)}.")
};
}
+12 -9
View File
@@ -1,15 +1,16 @@
using System.IO;
using System.IO;
using Stef.Validation;
namespace WireMock.Util
namespace WireMock.Util;
internal static class PathUtils
{
internal static class PathUtils
{
/// <summary>
/// Robust handling of the user defined path.
/// Also supports Unix and Windows platforms
/// </summary>
/// <param name="path">The path to clean</param>
public static string CleanPath(string path)
public static string? CleanPath(string? path)
{
return path?.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
}
@@ -18,7 +19,7 @@ namespace WireMock.Util
/// Removes leading directory separator chars from the filepath, which could break Path.Combine
/// </summary>
/// <param name="path">The path to remove the loading DirectorySeparatorChars</param>
public static string RemoveLeadingDirectorySeparators(string path)
public static string? RemoveLeadingDirectorySeparators(string? path)
{
return path?.TrimStart(new[] { Path.DirectorySeparatorChar });
}
@@ -28,9 +29,11 @@ namespace WireMock.Util
/// </summary>
/// <param name="root">The root path</param>
/// <param name="path">The path</param>
public static string Combine(string root, string path)
public static string Combine(string root, string? path)
{
return Path.Combine(root, RemoveLeadingDirectorySeparators(path));
}
Guard.NotNull(root);
var result = RemoveLeadingDirectorySeparators(path);
return result == null ? root : Path.Combine(root, result);
}
}
+1 -1
View File
@@ -4,5 +4,5 @@ namespace WireMock.Util;
internal static class SystemUtils
{
public static readonly string Version = typeof(SystemUtils).GetTypeInfo().Assembly.GetName().Version.ToString();
public static readonly string Version = typeof(SystemUtils).GetTypeInfo().Assembly.GetName().Version!.ToString();
}
+5
View File
@@ -140,6 +140,11 @@
<PackageReference Include="Scriban.Signed" Version="5.5.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<!--<PackageReference Include="System.Diagnostics.CodeAnalysis" Version="4.3.0" />-->
<PackageReference Include="Nullable" Version="1.3.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Server\WireMockServer.*.cs">
<DependentUpon>WireMockServer.cs</DependentUpon>
+61 -1
View File
@@ -1,5 +1,9 @@
using System.IO;
using System.Net;
using System.Text;
using FluentAssertions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
@@ -11,7 +15,7 @@ namespace WireMock.Net.Tests.Pact;
public class PactTests
{
[Fact]
public void SavePact_Get_Request()
public void SavePact_Get_Request_And_Response_WithBodyAsJson()
{
var server = WireMockServer.Start();
server
@@ -41,6 +45,62 @@ public class PactTests
server.SavePact(Path.Combine("../../../", "Pact", "files"), "pact-get.json");
}
[Fact]
public void SavePact_Get_Request_And_Response_WithBody_StringIsJson()
{
// Act
var server = WireMockServer.Start();
server
.Given(Request.Create()
.UsingGet()
.WithPath("/tester")
)
.RespondWith(
Response.Create()
.WithStatusCode(HttpStatusCode.OK)
.WithBody(@"{ foo: ""bar"" }")
);
var memoryStream = new MemoryStream();
server.SavePact(memoryStream);
var json = Encoding.UTF8.GetString(memoryStream.ToArray());
var pact = JsonConvert.DeserializeObject<WireMock.Pact.Models.V2.Pact>(json)!;
// Assert
pact.Interactions.Should().HaveCount(1);
var expectedBody = new JObject { { "foo", "bar" } };
pact.Interactions[0].Response.Body.Should().BeEquivalentTo(expectedBody);
}
[Fact]
public void SavePact_Get_Request_And_Response_WithBody_StringIsString()
{
// Act
var server = WireMockServer.Start();
server
.Given(Request.Create()
.UsingGet()
.WithPath("/tester")
)
.RespondWith(
Response.Create()
.WithStatusCode(HttpStatusCode.OK)
.WithBody("test")
);
var memoryStream = new MemoryStream();
server.SavePact(memoryStream);
var json = Encoding.UTF8.GetString(memoryStream.ToArray());
var pact = JsonConvert.DeserializeObject<WireMock.Pact.Models.V2.Pact>(json)!;
// Assert
pact.Interactions.Should().HaveCount(1);
pact.Interactions[0].Response.Body.Should().Be("test");
}
[Fact]
public void SavePact_Multiple_Requests()
{
@@ -2,10 +2,10 @@ using NFluent;
using WireMock.Settings;
using Xunit;
namespace WireMock.Net.Tests.Settings
namespace WireMock.Net.Tests.Settings;
public class SimpleCommandLineParserTests
{
public class SimpleCommandLineParserTests
{
private readonly SimpleCommandLineParser _parser;
public SimpleCommandLineParserTests()
@@ -20,9 +20,9 @@ namespace WireMock.Net.Tests.Settings
_parser.Parse(new[] { "--test1", "one", "--test2", "two", "--test3", "three" });
// Act
string value1 = _parser.GetStringValue("test1");
string value2 = _parser.GetStringValue("test2");
string value3 = _parser.GetStringValue("test3");
string? value1 = _parser.GetStringValue("test1");
string? value2 = _parser.GetStringValue("test2");
string? value3 = _parser.GetStringValue("test3");
// Assert
Check.That(value1).IsEqualTo("one");
@@ -37,9 +37,9 @@ namespace WireMock.Net.Tests.Settings
_parser.Parse(new[] { "--test1 one", "--test2 two", "--test3 three" });
// Act
string value1 = _parser.GetStringValue("test1");
string value2 = _parser.GetStringValue("test2");
string value3 = _parser.GetStringValue("test3");
string? value1 = _parser.GetStringValue("test1");
string? value2 = _parser.GetStringValue("test2");
string? value3 = _parser.GetStringValue("test3");
// Assert
Check.That(value1).IsEqualTo("one");
@@ -54,9 +54,9 @@ namespace WireMock.Net.Tests.Settings
_parser.Parse(new[] { "--test1 one", "--test2", "two", "--test3 three" });
// Act
string value1 = _parser.GetStringValue("test1");
string value2 = _parser.GetStringValue("test2");
string value3 = _parser.GetStringValue("test3");
string? value1 = _parser.GetStringValue("test1");
string? value2 = _parser.GetStringValue("test2");
string? value3 = _parser.GetStringValue("test3");
// Assert
Check.That(value1).IsEqualTo("one");
@@ -99,5 +99,4 @@ namespace WireMock.Net.Tests.Settings
Check.That(value3).IsEqualTo(100);
Check.That(value4).IsNull();
}
}
}
+28 -2
View File
@@ -13,7 +13,7 @@ namespace WireMock.Net.Tests.Util;
public class JsonUtilsTests
{
[Fact]
public void JsonUtils_ParseJTokenToObject()
public void JsonUtils_ParseJTokenToObject_For_String()
{
// Assign
object value = "test";
@@ -22,7 +22,33 @@ public class JsonUtilsTests
string result = JsonUtils.ParseJTokenToObject<string>(value);
// Assert
Check.That(result).IsEqualTo(default(string));
result.Should().Be("test");
}
[Fact]
public void JsonUtils_ParseJTokenToObject_For_Int()
{
// Assign
object value = 123;
// Act
var result = JsonUtils.ParseJTokenToObject<int>(value);
// Assert
result.Should().Be(123);
}
[Fact]
public void JsonUtils_ParseJTokenToObject_For_Invalid_Throws()
{
// Assign
object value = "{ }";
// Act
Action action = () => JsonUtils.ParseJTokenToObject<int>(value);
// Assert
action.Should().Throw<NotSupportedException>();
}
[Fact]
@@ -1,12 +1,12 @@
using NFluent;
using NFluent;
using System.IO;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests.Util
namespace WireMock.Net.Tests.Util;
public class PathUtilsTests
{
public class PathUtilsTests
{
[Theory]
[InlineData(@"subdirectory/MyXmlResponse.xml")]
[InlineData(@"subdirectory\MyXmlResponse.xml")]
@@ -40,5 +40,4 @@ namespace WireMock.Net.Tests.Util
// Assert
Check.That(withoutDirectorySeparators).Equals(expected);
}
}
}
@@ -3,10 +3,10 @@ using NFluent;
using WireMock.Util;
using Xunit;
namespace WireMock.Net.Tests.Util
namespace WireMock.Net.Tests.Util;
public class PortUtilsTests
{
public class PortUtilsTests
{
[Fact]
public void PortUtils_TryExtract_InvalidUrl_Returns_False()
{
@@ -85,10 +85,10 @@ namespace WireMock.Net.Tests.Util
bool result = PortUtils.TryExtract(url, out bool isHttps, out string proto, out string host, out int port);
// Assert
Check.That(result).IsTrue();
Check.That(proto).IsEqualTo("https");
Check.That(host).IsEqualTo("0.0.0.0");
Check.That(port).IsEqualTo(5000);
}
result.Should().BeTrue();
isHttps.Should().BeTrue();
proto.Should().Be("https");
host.Should().Be("0.0.0.0");
port.Should().Be(5000);
}
}