mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-01-11 21:10:32 +01:00
Update Transformer functionality to return value instead of string (#858)
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Scriban/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sigil/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stef/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=templated/@EntryIndexedValue">True</s:Boolean>
|
||||
<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>
|
||||
|
||||
@@ -1,36 +1,25 @@
|
||||
using System;
|
||||
namespace WireMock.Types;
|
||||
|
||||
namespace WireMock.Types
|
||||
/// <summary>
|
||||
/// Logic to use when replace a JSON node using the Transformer.
|
||||
/// </summary>
|
||||
public enum ReplaceNodeOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Flags to use when replace a JSON node using the Transformer.
|
||||
/// Try to evaluate a templated value.
|
||||
/// In case this is valid, return the value and if the value can be converted to a primitive type, use that value.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ReplaceNodeOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Default
|
||||
/// </summary>
|
||||
None = 0
|
||||
EvaluateAndTryToConvert = 0,
|
||||
|
||||
///// <summary>
|
||||
///// Replace boolean string value to a real boolean value. (This is used by default to maintain backward compatibility.)
|
||||
///// </summary>
|
||||
//Bool = 0b00000001,
|
||||
/// <summary>
|
||||
/// Try to evaluate a templated value.
|
||||
/// In case this is valid, return the value, else fallback to the parse behavior.
|
||||
/// </summary>
|
||||
Evaluate = 1,
|
||||
|
||||
///// <summary>
|
||||
///// Replace integer string value to a real integer value.
|
||||
///// </summary>
|
||||
//Integer = 0b00000010,
|
||||
|
||||
///// <summary>
|
||||
///// Replace long string value to a real long value.
|
||||
///// </summary>
|
||||
//Long = 0b00000100,
|
||||
|
||||
///// <summary>
|
||||
///// Replace all string values to a real values.
|
||||
///// </summary>
|
||||
//All = Bool | Integer | Long
|
||||
}
|
||||
/// <summary>
|
||||
/// Parse templated string to a templated string.
|
||||
/// (keep a templated string value as string value).
|
||||
/// </summary>
|
||||
Parse = 2
|
||||
}
|
||||
@@ -1,23 +1,22 @@
|
||||
namespace WireMock.Types
|
||||
namespace WireMock.Types;
|
||||
|
||||
/// <summary>
|
||||
/// The ResponseMessage Transformers
|
||||
/// </summary>
|
||||
public enum TransformerType
|
||||
{
|
||||
/// <summary>
|
||||
/// The ResponseMessage Transformers
|
||||
/// https://github.com/Handlebars-Net/Handlebars.Net
|
||||
/// </summary>
|
||||
public enum TransformerType
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/Handlebars-Net/Handlebars.Net
|
||||
/// </summary>
|
||||
Handlebars,
|
||||
Handlebars,
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/scriban/scriban : default
|
||||
/// </summary>
|
||||
Scriban,
|
||||
/// <summary>
|
||||
/// https://github.com/scriban/scriban : default
|
||||
/// </summary>
|
||||
Scriban,
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/scriban/scriban : DotLiquid
|
||||
/// </summary>
|
||||
ScribanDotLiquid
|
||||
}
|
||||
/// <summary>
|
||||
/// https://github.com/scriban/scriban : DotLiquid
|
||||
/// </summary>
|
||||
ScribanDotLiquid
|
||||
}
|
||||
@@ -51,14 +51,14 @@ internal class WebhookSender
|
||||
switch (webhookRequest.TransformerType)
|
||||
{
|
||||
case TransformerType.Handlebars:
|
||||
var factoryHandlebars = new HandlebarsContextFactory(_settings.FileSystemHandler, _settings.HandlebarsRegistrationCallback);
|
||||
transformer = new Transformer(factoryHandlebars);
|
||||
var factoryHandlebars = new HandlebarsContextFactory(_settings);
|
||||
transformer = new Transformer(_settings, factoryHandlebars);
|
||||
break;
|
||||
|
||||
case TransformerType.Scriban:
|
||||
case TransformerType.ScribanDotLiquid:
|
||||
var factoryDotLiquid = new ScribanContextFactory(_settings.FileSystemHandler, webhookRequest.TransformerType);
|
||||
transformer = new Transformer(factoryDotLiquid);
|
||||
transformer = new Transformer(_settings, factoryDotLiquid);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -29,5 +29,5 @@ public interface ITransformResponseBuilder : IDelayResponseBuilder
|
||||
/// <returns>
|
||||
/// The <see cref="IResponseBuilder"/>.
|
||||
/// </returns>
|
||||
IResponseBuilder WithTransformer(TransformerType transformerType = TransformerType.Handlebars, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.None);
|
||||
IResponseBuilder WithTransformer(TransformerType transformerType = TransformerType.Handlebars, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.Evaluate);
|
||||
}
|
||||
@@ -207,7 +207,7 @@ public partial class Response : IResponseBuilder
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.None)
|
||||
public IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.Evaluate)
|
||||
{
|
||||
UseTransformer = true;
|
||||
TransformerType = transformerType;
|
||||
@@ -314,14 +314,14 @@ public partial class Response : IResponseBuilder
|
||||
switch (TransformerType)
|
||||
{
|
||||
case TransformerType.Handlebars:
|
||||
var factoryHandlebars = new HandlebarsContextFactory(settings.FileSystemHandler, settings.HandlebarsRegistrationCallback);
|
||||
responseMessageTransformer = new Transformer(factoryHandlebars);
|
||||
var factoryHandlebars = new HandlebarsContextFactory(settings);
|
||||
responseMessageTransformer = new Transformer(settings, factoryHandlebars);
|
||||
break;
|
||||
|
||||
case TransformerType.Scriban:
|
||||
case TransformerType.ScribanDotLiquid:
|
||||
var factoryDotLiquid = new ScribanContextFactory(settings.FileSystemHandler, TransformerType);
|
||||
responseMessageTransformer = new Transformer(factoryDotLiquid);
|
||||
responseMessageTransformer = new Transformer(settings, factoryDotLiquid);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -39,7 +39,7 @@ internal static class WebhookMapper
|
||||
|
||||
if (!Enum.TryParse<ReplaceNodeOptions>(model.Request.TransformerReplaceNodeOptions, out var option))
|
||||
{
|
||||
option = ReplaceNodeOptions.None;
|
||||
option = ReplaceNodeOptions.Evaluate;
|
||||
}
|
||||
webhook.Request.TransformerReplaceNodeOptions = option;
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ public partial class WireMockServer
|
||||
|
||||
if (!Enum.TryParse<ReplaceNodeOptions>(responseModel.TransformerReplaceNodeOptions, out var option))
|
||||
{
|
||||
option = ReplaceNodeOptions.None;
|
||||
option = ReplaceNodeOptions.Evaluate;
|
||||
}
|
||||
responseBuilder = responseBuilder.WithTransformer(
|
||||
transformerType,
|
||||
|
||||
@@ -10,272 +10,279 @@ using WireMock.Logging;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.RegularExpressions;
|
||||
using WireMock.Types;
|
||||
using System.Globalization;
|
||||
#if USE_ASPNETCORE
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Settings
|
||||
namespace WireMock.Settings;
|
||||
|
||||
/// <summary>
|
||||
/// WireMockServerSettings
|
||||
/// </summary>
|
||||
public class WireMockServerSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// WireMockServerSettings
|
||||
/// Gets or sets the http port.
|
||||
/// </summary>
|
||||
public class WireMockServerSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the http port.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public int? Port { get; set; }
|
||||
[PublicAPI]
|
||||
public int? Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the use SSL.
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
[PublicAPI]
|
||||
public bool? UseSSL { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the use SSL.
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
[PublicAPI]
|
||||
public bool? UseSSL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines on which scheme (http/https) to host. (This overrides the <c>UseSSL</c> value).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public HostingScheme? HostingScheme { get; set; }
|
||||
/// <summary>
|
||||
/// Defines on which scheme (http/https) to host. (This overrides the <c>UseSSL</c> value).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public HostingScheme? HostingScheme { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to start admin interface.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? StartAdminInterface { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets whether to start admin interface.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? StartAdminInterface { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the static mappings should be read at startup.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? ReadStaticMappings { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets if the static mappings should be read at startup.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? ReadStaticMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Watch the static mapping files + folder for changes when running.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? WatchStaticMappings { get; set; }
|
||||
/// <summary>
|
||||
/// Watch the static mapping files + folder for changes when running.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? WatchStaticMappings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating whether subdirectories within the static mappings path should be monitored.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? WatchStaticMappingsInSubdirectories { get; set; }
|
||||
/// <summary>
|
||||
/// A value indicating whether subdirectories within the static mappings path should be monitored.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? WatchStaticMappingsInSubdirectories { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the proxy and record settings.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public ProxyAndRecordSettings? ProxyAndRecordSettings { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets if the proxy and record settings.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public ProxyAndRecordSettings? ProxyAndRecordSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the urls.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string[]? Urls { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the urls.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string[]? Urls { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// StartTimeout
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public int StartTimeout { get; set; } = 10000;
|
||||
/// <summary>
|
||||
/// StartTimeout
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public int StartTimeout { get; set; } = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Allow Partial Mapping (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? AllowPartialMapping { get; set; }
|
||||
/// <summary>
|
||||
/// Allow Partial Mapping (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? AllowPartialMapping { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The username needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string? AdminUsername { get; set; }
|
||||
/// <summary>
|
||||
/// The username needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string? AdminUsername { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The password needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string? AdminPassword { get; set; }
|
||||
/// <summary>
|
||||
/// The password needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string? AdminPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The AzureAD Tenant needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string? AdminAzureADTenant { get; set; }
|
||||
/// <summary>
|
||||
/// The AzureAD Tenant needed for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string? AdminAzureADTenant { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The AzureAD Audience / Resource for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string? AdminAzureADAudience { get; set; }
|
||||
/// <summary>
|
||||
/// The AzureAD Audience / Resource for __admin access.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string? AdminAzureADAudience { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The RequestLog expiration in hours (optional).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public int? RequestLogExpirationDuration { get; set; }
|
||||
/// <summary>
|
||||
/// The RequestLog expiration in hours (optional).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public int? RequestLogExpirationDuration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The MaxRequestLog count (optional).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public int? MaxRequestLogCount { get; set; }
|
||||
/// <summary>
|
||||
/// The MaxRequestLog count (optional).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public int? MaxRequestLogCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action which is called (with the IAppBuilder or IApplicationBuilder) before the internal WireMockMiddleware is initialized. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<object>? PreWireMockMiddlewareInit { get; set; }
|
||||
/// <summary>
|
||||
/// Action which is called (with the IAppBuilder or IApplicationBuilder) before the internal WireMockMiddleware is initialized. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<object>? PreWireMockMiddlewareInit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action which is called (with the IAppBuilder or IApplicationBuilder) after the internal WireMockMiddleware is initialized. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<object>? PostWireMockMiddlewareInit { get; set; }
|
||||
/// <summary>
|
||||
/// Action which is called (with the IAppBuilder or IApplicationBuilder) after the internal WireMockMiddleware is initialized. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<object>? PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
/// <summary>
|
||||
/// Action which is called with IServiceCollection when ASP.NET Core DI is being configured. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
|
||||
/// <summary>
|
||||
/// Action which is called with IServiceCollection when ASP.NET Core DI is being configured. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Policies to use when using CORS. By default CORS is disabled. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
|
||||
/// <summary>
|
||||
/// Policies to use when using CORS. By default CORS is disabled. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The IWireMockLogger which logs Debug, Info, Warning or Error
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public IWireMockLogger Logger { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// The IWireMockLogger which logs Debug, Info, Warning or Error
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public IWireMockLogger Logger { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Handler to interact with the file system to read and write static mapping files.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public IFileSystemHandler FileSystemHandler { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Handler to interact with the file system to read and write static mapping files.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public IFileSystemHandler FileSystemHandler { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Action which can be used to add additional Handlebars registrations. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<IHandlebars, IFileSystemHandler>? HandlebarsRegistrationCallback { get; set; }
|
||||
/// <summary>
|
||||
/// Action which can be used to add additional Handlebars registrations. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<IHandlebars, IFileSystemHandler>? HandlebarsRegistrationCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow the usage of CSharpCodeMatcher (default is not allowed).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? AllowCSharpCodeMatcher { get; set; }
|
||||
/// <summary>
|
||||
/// Allow the usage of CSharpCodeMatcher (default is not allowed).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? AllowCSharpCodeMatcher { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow a Body for all HTTP Methods. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
/// <summary>
|
||||
/// Allow a Body for all HTTP Methods. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow only a HttpStatus Code in the response which is defined. (default set to false).
|
||||
/// - false : also null, 0, empty or invalid HttpStatus codes are allowed.
|
||||
/// - true : only codes defined in <see cref="System.Net.HttpStatusCode"/> are allowed.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? AllowOnlyDefinedHttpStatusCodeInResponse { get; set; }
|
||||
/// <summary>
|
||||
/// Allow only a HttpStatus Code in the response which is defined. (default set to false).
|
||||
/// - false : also null, 0, empty or invalid HttpStatus codes are allowed.
|
||||
/// - true : only codes defined in <see cref="System.Net.HttpStatusCode"/> are allowed.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? AllowOnlyDefinedHttpStatusCodeInResponse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true to disable Json deserialization when processing requests. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? DisableJsonBodyParsing { get; set; }
|
||||
/// <summary>
|
||||
/// Set to true to disable Json deserialization when processing requests. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? DisableJsonBodyParsing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disable support for GZip and Deflate request body decompression. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? DisableRequestBodyDecompressing { get; set; }
|
||||
/// <summary>
|
||||
/// Disable support for GZip and Deflate request body decompression. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? DisableRequestBodyDecompressing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handle all requests synchronously. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? HandleRequestsSynchronously { get; set; }
|
||||
/// <summary>
|
||||
/// Handle all requests synchronously. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? HandleRequestsSynchronously { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Throw an exception when the <see cref="IMatcher"/> fails because of invalid input. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? ThrowExceptionWhenMatcherFails { get; set; }
|
||||
/// <summary>
|
||||
/// Throw an exception when the <see cref="IMatcher"/> fails because of invalid input. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? ThrowExceptionWhenMatcherFails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If https is used, these settings can be used to configure the CertificateSettings in case a custom certificate instead the default .NET certificate should be used.
|
||||
///
|
||||
/// X509StoreName and X509StoreLocation should be defined
|
||||
/// OR
|
||||
/// X509CertificateFilePath and X509CertificatePassword should be defined
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public WireMockCertificateSettings? CertificateSettings { get; set; }
|
||||
/// <summary>
|
||||
/// If https is used, these settings can be used to configure the CertificateSettings in case a custom certificate instead the default .NET certificate should be used.
|
||||
///
|
||||
/// X509StoreName and X509StoreLocation should be defined
|
||||
/// OR
|
||||
/// X509CertificateFilePath and X509CertificatePassword should be defined
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public WireMockCertificateSettings? CertificateSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines if custom CertificateSettings are defined
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool CustomCertificateDefined => CertificateSettings?.IsDefined == true;
|
||||
/// <summary>
|
||||
/// Defines if custom CertificateSettings are defined
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool CustomCertificateDefined => CertificateSettings?.IsDefined == true;
|
||||
|
||||
/// <summary>
|
||||
/// Defines the global IWebhookSettings to use.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public WebhookSettings? WebhookSettings { get; set; }
|
||||
/// <summary>
|
||||
/// Defines the global IWebhookSettings to use.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public WebhookSettings? WebhookSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Use the <see cref="RegexExtended"/> instead of the default <see cref="Regex"/> (default set to true).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? UseRegexExtended { get; set; } = true;
|
||||
/// <summary>
|
||||
/// Use the <see cref="RegexExtended"/> instead of the default <see cref="Regex"/> (default set to true).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? UseRegexExtended { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Save unmatched requests to a file using the <see cref="IFileSystemHandler"/> (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? SaveUnmatchedRequests { get; set; }
|
||||
/// <summary>
|
||||
/// Save unmatched requests to a file using the <see cref="IFileSystemHandler"/> (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? SaveUnmatchedRequests { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Don't save the response-string in the LogEntry when WithBody(Func{IRequestMessage, string}) or WithBody(Func{IRequestMessage, Task{string}}) is used. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? DoNotSaveDynamicResponseInLogEntry { get; set; }
|
||||
/// <summary>
|
||||
/// Don't save the response-string in the LogEntry when WithBody(Func{IRequestMessage, string}) or WithBody(Func{IRequestMessage, Task{string}}) is used. (default set to false).
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool? DoNotSaveDynamicResponseInLogEntry { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// See <seealso cref="QueryParameterMultipleValueSupport"/>.
|
||||
///
|
||||
/// Default value = "All".
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
|
||||
/// <summary>
|
||||
/// See <seealso cref="QueryParameterMultipleValueSupport"/>.
|
||||
///
|
||||
/// Default value = "All".
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Custom matcher mappings for static mappings
|
||||
/// </summary>
|
||||
[PublicAPI, JsonIgnore]
|
||||
public IDictionary<string, Func<MatcherModel, IMatcher>>? CustomMatcherMappings { get; set; }
|
||||
/// <summary>
|
||||
/// Custom matcher mappings for static mappings
|
||||
/// </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; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The <see cref="JsonSerializerSettings"/> used when the a JSON response is generated.
|
||||
/// </summary>
|
||||
[PublicAPI, JsonIgnore]
|
||||
public JsonSerializerSettings? JsonSerializerSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Culture to use.
|
||||
/// Currently used for:
|
||||
/// - Handlebars Transformer
|
||||
/// </summary>
|
||||
public CultureInfo Culture { get; set; } = CultureInfo.CurrentCulture;
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Stef.Validation;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Settings;
|
||||
|
||||
@@ -55,7 +58,8 @@ public static class WireMockServerSettingsParser
|
||||
WatchStaticMappingsInSubdirectories = parser.GetBoolValue("WatchStaticMappingsInSubdirectories"),
|
||||
HostingScheme = parser.GetEnumValue<HostingScheme>(nameof(WireMockServerSettings.HostingScheme)),
|
||||
DoNotSaveDynamicResponseInLogEntry = parser.GetBoolValue(nameof(WireMockServerSettings.DoNotSaveDynamicResponseInLogEntry)),
|
||||
QueryParameterMultipleValueSupport = parser.GetEnumValue<QueryParameterMultipleValueSupport>(nameof(WireMockServerSettings.QueryParameterMultipleValueSupport))
|
||||
QueryParameterMultipleValueSupport = parser.GetEnumValue<QueryParameterMultipleValueSupport>(nameof(WireMockServerSettings.QueryParameterMultipleValueSupport)),
|
||||
Culture = parser.GetValue(nameof(WireMockServerSettings.Culture), strings => CultureInfoUtils.Parse(strings.FirstOrDefault()), CultureInfo.CurrentCulture)
|
||||
};
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
using System;
|
||||
using HandlebarsDotNet;
|
||||
using HandlebarsDotNet.Helpers.Attributes;
|
||||
using HandlebarsDotNet.Helpers.Enums;
|
||||
using HandlebarsDotNet.Helpers.Helpers;
|
||||
using Stef.Validation;
|
||||
using WireMock.Handlers;
|
||||
|
||||
namespace WireMock.Transformers.Handlebars
|
||||
namespace WireMock.Transformers.Handlebars;
|
||||
|
||||
internal class FileHelpers : BaseHelpers, IHelpers
|
||||
{
|
||||
internal class FileHelpers : BaseHelpers, IHelpers
|
||||
private readonly IFileSystemHandler _fileSystemHandler;
|
||||
|
||||
public FileHelpers(IHandlebars context, IFileSystemHandler fileSystemHandler) : base(context)
|
||||
{
|
||||
private readonly IFileSystemHandler _fileSystemHandler;
|
||||
_fileSystemHandler = Guard.NotNull(fileSystemHandler);
|
||||
}
|
||||
|
||||
public FileHelpers(IHandlebars context, IFileSystemHandler fileSystemHandler) : base(context)
|
||||
{
|
||||
_fileSystemHandler = fileSystemHandler ?? throw new ArgumentNullException(nameof(fileSystemHandler));
|
||||
}
|
||||
|
||||
[HandlebarsWriter(WriterType.String, usage: HelperUsage.Both, passContext: true, name: "File")]
|
||||
public string Read(Context context, string path)
|
||||
{
|
||||
var templateFunc = Context.Compile(path);
|
||||
string transformed = templateFunc(context.Value);
|
||||
return _fileSystemHandler.ReadResponseBodyAsString(transformed);
|
||||
}
|
||||
[HandlebarsWriter(WriterType.String, usage: HelperUsage.Both, passContext: true, name: "File")]
|
||||
public string Read(Context context, string path)
|
||||
{
|
||||
var templateFunc = Context.Compile(path);
|
||||
string transformed = templateFunc(context.Value);
|
||||
return _fileSystemHandler.ReadResponseBodyAsString(transformed);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,35 @@
|
||||
using HandlebarsDotNet;
|
||||
using HandlebarsDotNet.Helpers.Extensions;
|
||||
using Stef.Validation;
|
||||
using WireMock.Handlers;
|
||||
|
||||
namespace WireMock.Transformers.Handlebars
|
||||
namespace WireMock.Transformers.Handlebars;
|
||||
|
||||
internal class HandlebarsContext : IHandlebarsContext
|
||||
{
|
||||
internal class HandlebarsContext : IHandlebarsContext
|
||||
public IHandlebars Handlebars { get; }
|
||||
|
||||
public IFileSystemHandler FileSystemHandler { get; }
|
||||
|
||||
public HandlebarsContext(IHandlebars handlebars, IFileSystemHandler fileSystemHandler)
|
||||
{
|
||||
public IHandlebars Handlebars { get; set; }
|
||||
Handlebars = Guard.NotNull(handlebars);
|
||||
FileSystemHandler = Guard.NotNull(fileSystemHandler);
|
||||
}
|
||||
|
||||
public IFileSystemHandler FileSystemHandler { get; set; }
|
||||
public string ParseAndRender(string text, object model)
|
||||
{
|
||||
var template = Handlebars.Compile(text);
|
||||
return template(model);
|
||||
}
|
||||
|
||||
public string ParseAndRender(string text, object model)
|
||||
public object? ParseAndEvaluate(string text, object model)
|
||||
{
|
||||
if (Handlebars.TryEvaluate(text, model, out var result) && result is not UndefinedBindingResult)
|
||||
{
|
||||
var template = Handlebars.Compile(text);
|
||||
return template(model);
|
||||
return result;
|
||||
}
|
||||
|
||||
return ParseAndRender(text, model);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,30 @@
|
||||
using System;
|
||||
using HandlebarsDotNet;
|
||||
using Stef.Validation;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Settings;
|
||||
|
||||
namespace WireMock.Transformers.Handlebars;
|
||||
|
||||
internal class HandlebarsContextFactory : ITransformerContextFactory
|
||||
{
|
||||
private readonly IFileSystemHandler _fileSystemHandler;
|
||||
private readonly Action<IHandlebars, IFileSystemHandler>? _action;
|
||||
private readonly WireMockServerSettings _settings;
|
||||
|
||||
public HandlebarsContextFactory(IFileSystemHandler fileSystemHandler, Action<IHandlebars, IFileSystemHandler>? action)
|
||||
public HandlebarsContextFactory(WireMockServerSettings settings)
|
||||
{
|
||||
_fileSystemHandler = Guard.NotNull(fileSystemHandler);
|
||||
_action = action;
|
||||
_settings = Guard.NotNull(settings);
|
||||
}
|
||||
|
||||
public ITransformerContext Create()
|
||||
{
|
||||
var handlebars = HandlebarsDotNet.Handlebars.Create();
|
||||
|
||||
WireMockHandlebarsHelpers.Register(handlebars, _fileSystemHandler);
|
||||
|
||||
_action?.Invoke(handlebars, _fileSystemHandler);
|
||||
|
||||
return new HandlebarsContext
|
||||
var config = new HandlebarsConfiguration
|
||||
{
|
||||
Handlebars = handlebars,
|
||||
FileSystemHandler = _fileSystemHandler
|
||||
FormatProvider = _settings.Culture
|
||||
};
|
||||
var handlebars = HandlebarsDotNet.Handlebars.Create(config);
|
||||
|
||||
WireMockHandlebarsHelpers.Register(handlebars, _settings.FileSystemHandler);
|
||||
|
||||
_settings.HandlebarsRegistrationCallback?.Invoke(handlebars, _settings.FileSystemHandler);
|
||||
|
||||
return new HandlebarsContext(handlebars, _settings.FileSystemHandler);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
using HandlebarsDotNet;
|
||||
using HandlebarsDotNet;
|
||||
|
||||
namespace WireMock.Transformers.Handlebars
|
||||
namespace WireMock.Transformers.Handlebars;
|
||||
|
||||
interface IHandlebarsContext : ITransformerContext
|
||||
{
|
||||
interface IHandlebarsContext : ITransformerContext
|
||||
{
|
||||
IHandlebars Handlebars { get; set; }
|
||||
}
|
||||
IHandlebars Handlebars { get; }
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Handlers;
|
||||
|
||||
namespace WireMock.Transformers
|
||||
namespace WireMock.Transformers;
|
||||
|
||||
internal interface ITransformerContext
|
||||
{
|
||||
interface ITransformerContext
|
||||
{
|
||||
IFileSystemHandler FileSystemHandler { get; set; }
|
||||
IFileSystemHandler FileSystemHandler { get; }
|
||||
|
||||
string ParseAndRender(string text, object model);
|
||||
}
|
||||
string ParseAndRender(string text, object model);
|
||||
|
||||
object? ParseAndEvaluate(string text, object model);
|
||||
}
|
||||
@@ -3,25 +3,30 @@ using Stef.Validation;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Types;
|
||||
|
||||
namespace WireMock.Transformers.Scriban
|
||||
namespace WireMock.Transformers.Scriban;
|
||||
|
||||
internal class ScribanContext : ITransformerContext
|
||||
{
|
||||
internal class ScribanContext : ITransformerContext
|
||||
private readonly TransformerType _transformerType;
|
||||
|
||||
public IFileSystemHandler FileSystemHandler { get; }
|
||||
|
||||
public ScribanContext(IFileSystemHandler fileSystemHandler, TransformerType transformerType)
|
||||
{
|
||||
private readonly TransformerType _transformerType;
|
||||
FileSystemHandler = Guard.NotNull(fileSystemHandler);
|
||||
_transformerType = transformerType;
|
||||
}
|
||||
|
||||
public IFileSystemHandler FileSystemHandler { get; set; }
|
||||
public string ParseAndRender(string text, object model)
|
||||
{
|
||||
var template = _transformerType == TransformerType.ScribanDotLiquid ? Template.ParseLiquid(text) : Template.Parse(text);
|
||||
|
||||
public ScribanContext(IFileSystemHandler fileSystemHandler, TransformerType transformerType)
|
||||
{
|
||||
FileSystemHandler = Guard.NotNull(fileSystemHandler);
|
||||
_transformerType = transformerType;
|
||||
}
|
||||
return template.Render(model, member => member.Name);
|
||||
}
|
||||
|
||||
public string ParseAndRender(string text, object model)
|
||||
{
|
||||
var template = _transformerType == TransformerType.ScribanDotLiquid ? Template.ParseLiquid(text) : Template.Parse(text);
|
||||
|
||||
return template.Render(model, member => member.Name);
|
||||
}
|
||||
public object? ParseAndEvaluate(string text, object model)
|
||||
{
|
||||
// In case of Scriban, call ParseAndRender.
|
||||
return ParseAndRender(text, model);
|
||||
}
|
||||
}
|
||||
@@ -2,22 +2,21 @@ using WireMock.Handlers;
|
||||
using WireMock.Types;
|
||||
using Stef.Validation;
|
||||
|
||||
namespace WireMock.Transformers.Scriban
|
||||
namespace WireMock.Transformers.Scriban;
|
||||
|
||||
internal class ScribanContextFactory : ITransformerContextFactory
|
||||
{
|
||||
internal class ScribanContextFactory : ITransformerContextFactory
|
||||
private readonly IFileSystemHandler _fileSystemHandler;
|
||||
private readonly TransformerType _transformerType;
|
||||
|
||||
public ScribanContextFactory(IFileSystemHandler fileSystemHandler, TransformerType transformerType)
|
||||
{
|
||||
private readonly IFileSystemHandler _fileSystemHandler;
|
||||
private readonly TransformerType _transformerType;
|
||||
_fileSystemHandler = Guard.NotNull(fileSystemHandler);
|
||||
_transformerType = Guard.Condition(transformerType, t => t is TransformerType.Scriban or TransformerType.ScribanDotLiquid);
|
||||
}
|
||||
|
||||
public ScribanContextFactory(IFileSystemHandler fileSystemHandler, TransformerType transformerType)
|
||||
{
|
||||
_fileSystemHandler = Guard.NotNull(fileSystemHandler);
|
||||
_transformerType = Guard.Condition(transformerType, t => t == TransformerType.Scriban || t == TransformerType.ScribanDotLiquid);
|
||||
}
|
||||
|
||||
public ITransformerContext Create()
|
||||
{
|
||||
return new ScribanContext(_fileSystemHandler, _transformerType);
|
||||
}
|
||||
public ITransformerContext Create()
|
||||
{
|
||||
return new ScribanContext(_fileSystemHandler, _transformerType);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Stef.Validation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
@@ -11,11 +13,19 @@ namespace WireMock.Transformers;
|
||||
|
||||
internal class Transformer : ITransformer
|
||||
{
|
||||
private static readonly Type[] SupportedTypes = { typeof(bool), typeof(long), typeof(int), typeof(double), typeof(Guid), typeof(DateTime), typeof(TimeSpan), typeof(Uri) };
|
||||
|
||||
private readonly JsonSerializer _jsonSerializer;
|
||||
private readonly ITransformerContextFactory _factory;
|
||||
|
||||
public Transformer(ITransformerContextFactory factory)
|
||||
public Transformer(WireMockServerSettings settings, ITransformerContextFactory factory)
|
||||
{
|
||||
_factory = Guard.NotNull(factory);
|
||||
|
||||
_jsonSerializer = new JsonSerializer
|
||||
{
|
||||
Culture = Guard.NotNull(settings).Culture
|
||||
};
|
||||
}
|
||||
|
||||
public IBodyData? TransformBody(
|
||||
@@ -109,7 +119,7 @@ internal class Transformer : ITransformer
|
||||
});
|
||||
}
|
||||
|
||||
private static IBodyData? TransformBodyData(ITransformerContext transformerContext, ReplaceNodeOptions options, TransformModel model, IBodyData original, bool useTransformerForBodyAsFile)
|
||||
private IBodyData? TransformBodyData(ITransformerContext transformerContext, ReplaceNodeOptions options, TransformModel model, IBodyData original, bool useTransformerForBodyAsFile)
|
||||
{
|
||||
return original.DetectedBodyType switch
|
||||
{
|
||||
@@ -139,33 +149,33 @@ internal class Transformer : ITransformer
|
||||
return newHeaders;
|
||||
}
|
||||
|
||||
private static IBodyData TransformBodyAsJson(ITransformerContext handlebarsContext, ReplaceNodeOptions options, object model, IBodyData original)
|
||||
private IBodyData TransformBodyAsJson(ITransformerContext transformerContext, ReplaceNodeOptions options, object model, IBodyData original)
|
||||
{
|
||||
JToken? jToken = null;
|
||||
switch (original.BodyAsJson)
|
||||
{
|
||||
case JObject bodyAsJObject:
|
||||
jToken = bodyAsJObject.DeepClone();
|
||||
WalkNode(handlebarsContext, options, jToken, model);
|
||||
WalkNode(transformerContext, options, jToken, model);
|
||||
break;
|
||||
|
||||
case JArray bodyAsJArray:
|
||||
jToken = bodyAsJArray.DeepClone();
|
||||
WalkNode(handlebarsContext, options, jToken, model);
|
||||
WalkNode(transformerContext, options, jToken, model);
|
||||
break;
|
||||
|
||||
case Array bodyAsArray:
|
||||
jToken = JArray.FromObject(bodyAsArray);
|
||||
WalkNode(handlebarsContext, options, jToken, model);
|
||||
jToken = JArray.FromObject(bodyAsArray, _jsonSerializer);
|
||||
WalkNode(transformerContext, options, jToken, model);
|
||||
break;
|
||||
|
||||
case string bodyAsString:
|
||||
jToken = ReplaceSingleNode(handlebarsContext, options, bodyAsString, model);
|
||||
jToken = ReplaceSingleNode(transformerContext, options, bodyAsString, model);
|
||||
break;
|
||||
|
||||
case not null:
|
||||
jToken = JObject.FromObject(original.BodyAsJson);
|
||||
WalkNode(handlebarsContext, options, jToken, model);
|
||||
jToken = JObject.FromObject(original.BodyAsJson, _jsonSerializer);
|
||||
WalkNode(transformerContext, options, jToken, model);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -178,9 +188,9 @@ internal class Transformer : ITransformer
|
||||
};
|
||||
}
|
||||
|
||||
private static JToken ReplaceSingleNode(ITransformerContext handlebarsContext, ReplaceNodeOptions options, string stringValue, object model)
|
||||
private JToken ReplaceSingleNode(ITransformerContext transformerContext, ReplaceNodeOptions options, string stringValue, object model)
|
||||
{
|
||||
string transformedString = handlebarsContext.ParseAndRender(stringValue, model);
|
||||
string transformedString = transformerContext.ParseAndRender(stringValue, model);
|
||||
|
||||
if (!string.Equals(stringValue, transformedString))
|
||||
{
|
||||
@@ -202,7 +212,7 @@ internal class Transformer : ITransformer
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
private static void WalkNode(ITransformerContext handlebarsContext, ReplaceNodeOptions options, JToken node, object model)
|
||||
private void WalkNode(ITransformerContext transformerContext, ReplaceNodeOptions options, JToken node, object model)
|
||||
{
|
||||
switch (node.Type)
|
||||
{
|
||||
@@ -210,7 +220,7 @@ internal class Transformer : ITransformer
|
||||
// In case of Object, loop all children. Do a ToArray() to avoid `Collection was modified` exceptions.
|
||||
foreach (var child in node.Children<JProperty>().ToArray())
|
||||
{
|
||||
WalkNode(handlebarsContext, options, child.Value, model);
|
||||
WalkNode(transformerContext, options, child.Value, model);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -218,7 +228,7 @@ internal class Transformer : ITransformer
|
||||
// In case of Array, loop all items. Do a ToArray() to avoid `Collection was modified` exceptions.
|
||||
foreach (var child in node.Children().ToArray())
|
||||
{
|
||||
WalkNode(handlebarsContext, options, child, model);
|
||||
WalkNode(transformerContext, options, child, model);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -230,8 +240,8 @@ internal class Transformer : ITransformer
|
||||
return;
|
||||
}
|
||||
|
||||
string transformed = handlebarsContext.ParseAndRender(stringValue!, model);
|
||||
if (!string.Equals(stringValue, transformed))
|
||||
var transformed = transformerContext.ParseAndEvaluate(stringValue, model);
|
||||
if (!Equals(stringValue, transformed))
|
||||
{
|
||||
ReplaceNodeValue(options, node, transformed);
|
||||
}
|
||||
@@ -240,44 +250,88 @@ internal class Transformer : ITransformer
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedParameter.Local
|
||||
private static void ReplaceNodeValue(ReplaceNodeOptions options, JToken node, string transformedString)
|
||||
private void ReplaceNodeValue(ReplaceNodeOptions options, JToken node, object? transformedValue)
|
||||
{
|
||||
StringUtils.TryParseQuotedString(transformedString, out var result, out _);
|
||||
if (bool.TryParse(result, out var valueAsBoolean) || bool.TryParse(transformedString, out valueAsBoolean))
|
||||
switch (transformedValue)
|
||||
{
|
||||
node.Replace(valueAsBoolean);
|
||||
return;
|
||||
}
|
||||
case JValue jValue:
|
||||
node.Replace(jValue);
|
||||
return;
|
||||
|
||||
JToken value;
|
||||
try
|
||||
{
|
||||
// Try to convert this string into a JsonObject
|
||||
value = JToken.Parse(transformedString);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
// Ignore JsonException and just keep string value and convert to JToken
|
||||
value = transformedString;
|
||||
}
|
||||
case string transformedString:
|
||||
if (TryConvert(transformedString, out var convertedFromStringValue))
|
||||
{
|
||||
node.Replace(JToken.FromObject(convertedFromStringValue, _jsonSerializer));
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Replace(ParseAsJObject(transformedString));
|
||||
}
|
||||
break;
|
||||
|
||||
node.Replace(value);
|
||||
case WireMockList<string> strings:
|
||||
switch (strings.Count)
|
||||
{
|
||||
case 1:
|
||||
node.Replace(ParseAsJObject(strings[0]));
|
||||
return;
|
||||
|
||||
case > 1:
|
||||
node.Replace(JToken.FromObject(strings.ToArray(), _jsonSerializer));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case { }:
|
||||
if (TryConvert(transformedValue, out var convertedValue))
|
||||
{
|
||||
node.Replace(JToken.FromObject(convertedValue, _jsonSerializer));
|
||||
}
|
||||
return;
|
||||
|
||||
default: // It's null, skip it. Maybe remove it ?
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static IBodyData TransformBodyAsString(ITransformerContext handlebarsContext, object model, IBodyData original)
|
||||
private static JToken ParseAsJObject(string stringValue)
|
||||
{
|
||||
return JsonUtils.TryParseAsJObject(stringValue, out var parsedAsjObject) ? parsedAsjObject : stringValue;
|
||||
}
|
||||
|
||||
private static bool TryConvert(object? transformedValue, [NotNullWhen(true)] out object? convertedValue)
|
||||
{
|
||||
foreach (var supportedType in SupportedTypes)
|
||||
{
|
||||
try
|
||||
{
|
||||
convertedValue = Convert.ChangeType(transformedValue, supportedType);
|
||||
return convertedValue is not null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
convertedValue = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IBodyData TransformBodyAsString(ITransformerContext transformerContext, object model, IBodyData original)
|
||||
{
|
||||
return new BodyData
|
||||
{
|
||||
Encoding = original.Encoding,
|
||||
DetectedBodyType = original.DetectedBodyType,
|
||||
DetectedBodyTypeFromContentType = original.DetectedBodyTypeFromContentType,
|
||||
BodyAsString = handlebarsContext.ParseAndRender(original.BodyAsString!, model)
|
||||
BodyAsString = transformerContext.ParseAndRender(original.BodyAsString!, model)
|
||||
};
|
||||
}
|
||||
|
||||
private static IBodyData TransformBodyAsFile(ITransformerContext handlebarsContext, object model, IBodyData original, bool useTransformerForBodyAsFile)
|
||||
private static IBodyData TransformBodyAsFile(ITransformerContext transformerContext, object model, IBodyData original, bool useTransformerForBodyAsFile)
|
||||
{
|
||||
string transformedBodyAsFilename = handlebarsContext.ParseAndRender(original.BodyAsFile!, model);
|
||||
string transformedBodyAsFilename = transformerContext.ParseAndRender(original.BodyAsFile!, model);
|
||||
|
||||
if (!useTransformerForBodyAsFile)
|
||||
{
|
||||
@@ -289,12 +343,12 @@ internal class Transformer : ITransformer
|
||||
};
|
||||
}
|
||||
|
||||
string text = handlebarsContext.FileSystemHandler.ReadResponseBodyAsString(transformedBodyAsFilename);
|
||||
string text = transformerContext.FileSystemHandler.ReadResponseBodyAsString(transformedBodyAsFilename);
|
||||
return new BodyData
|
||||
{
|
||||
DetectedBodyType = BodyType.String,
|
||||
DetectedBodyTypeFromContentType = original.DetectedBodyTypeFromContentType,
|
||||
BodyAsString = handlebarsContext.ParseAndRender(text, model),
|
||||
BodyAsString = transformerContext.ParseAndRender(text, model),
|
||||
BodyAsFile = transformedBodyAsFilename
|
||||
};
|
||||
}
|
||||
|
||||
40
src/WireMock.Net/Util/CultureInfoExtensions.cs
Normal file
40
src/WireMock.Net/Util/CultureInfoExtensions.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace WireMock.Util;
|
||||
|
||||
internal static class CultureInfoUtils
|
||||
{
|
||||
public static CultureInfo Parse(string? value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return CultureInfo.CurrentCulture;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
#if !NETSTANDARD1_3
|
||||
if (int.TryParse(value, out var culture))
|
||||
{
|
||||
return new CultureInfo(culture);
|
||||
}
|
||||
#endif
|
||||
if (string.Equals(value, nameof(CultureInfo.CurrentCulture), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return CultureInfo.CurrentCulture;
|
||||
}
|
||||
|
||||
if (string.Equals(value, nameof(CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return CultureInfo.InvariantCulture;
|
||||
}
|
||||
|
||||
return new CultureInfo(value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return CultureInfo.CurrentCulture;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,8 +87,8 @@
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
<PackageReference Include="Scriban.Signed" Version="2.1.4" />
|
||||
<PackageReference Include="Nullable" Version="1.3.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -163,13 +163,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Handlebars.Net.Helpers" Version="2.3.10" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.3.10" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.3.10" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.3.10" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.3.10" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.3.10" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.3.10" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers" Version="2.3.11" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.3.11" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.3.11" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.3.11" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.3.11" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.3.11" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.3.11" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -108,7 +108,7 @@ public class ResponseWithHandlebarsJsonPathTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
JObject j = JObject.FromObject(response.Message.BodyData.BodyAsJson);
|
||||
JObject j = JObject.FromObject(response.Message.BodyData.BodyAsJson!);
|
||||
Check.That(j["x"].Value<long>()).Equals(99);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ResponseWithHandlebarsRandomTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(ReplaceNodeOptions.None, JTokenType.Integer)]
|
||||
[InlineData(ReplaceNodeOptions.Evaluate, JTokenType.Integer)]
|
||||
//[InlineData(ReplaceNodeOptions.Bool, JTokenType.String)]
|
||||
//[InlineData(ReplaceNodeOptions.Integer, JTokenType.Integer)]
|
||||
//[InlineData(ReplaceNodeOptions.Bool | ReplaceNodeOptions.Integer, JTokenType.Integer)]
|
||||
|
||||
@@ -14,6 +14,8 @@ using WireMock.Settings;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
using Xunit;
|
||||
using System.Globalization;
|
||||
using CultureAwareTesting.xUnit;
|
||||
#if NET452
|
||||
using Microsoft.Owin;
|
||||
#else
|
||||
@@ -24,6 +26,7 @@ namespace WireMock.Net.Tests.ResponseBuilders;
|
||||
|
||||
public class ResponseWithTransformerTests
|
||||
{
|
||||
private readonly Mock<IFileSystemHandler> _filesystemHandlerMock;
|
||||
private readonly WireMockServerSettings _settings = new();
|
||||
private const string ClientIp = "::1";
|
||||
|
||||
@@ -33,10 +36,10 @@ public class ResponseWithTransformerTests
|
||||
{
|
||||
_mappingMock = new Mock<IMapping>();
|
||||
|
||||
var filesystemHandlerMock = new Mock<IFileSystemHandler>(MockBehavior.Strict);
|
||||
filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny<string>())).Returns("abc");
|
||||
_filesystemHandlerMock = new Mock<IFileSystemHandler>(MockBehavior.Strict);
|
||||
_filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny<string>())).Returns("abc");
|
||||
|
||||
_settings.FileSystemHandler = filesystemHandlerMock.Object;
|
||||
_settings.FileSystemHandler = _filesystemHandlerMock.Object;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -333,7 +336,7 @@ public class ResponseWithTransformerTests
|
||||
// Assert
|
||||
Check.That(response.Message.BodyData!.BodyAsString).Equals("test");
|
||||
Check.That(response.Message.Headers).ContainsKey("x");
|
||||
Check.That(response.Message.Headers["x"]).Contains("text/plain");
|
||||
Check.That(response.Message.Headers!["x"]).Contains("text/plain");
|
||||
Check.That(response.Message.Headers["x"]).Contains("http://localhost/foo");
|
||||
}
|
||||
|
||||
@@ -358,7 +361,7 @@ public class ResponseWithTransformerTests
|
||||
// Assert
|
||||
Check.That(response.Message.BodyData!.BodyAsString).Equals("test");
|
||||
Check.That(response.Message.Headers).ContainsKey("x");
|
||||
Check.That(response.Message.Headers["x"]).Contains("text/plain");
|
||||
Check.That(response.Message.Headers!["x"]).Contains("text/plain");
|
||||
Check.That(response.Message.Headers["x"]).Contains("http://localhost/foo");
|
||||
}
|
||||
|
||||
@@ -394,7 +397,7 @@ public class ResponseWithTransformerTests
|
||||
public async Task Response_ProvideResponse_Transformer_WithBodyAsJson_ResultAsObject(TransformerType transformerType)
|
||||
{
|
||||
// Assign
|
||||
string jsonString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"WireMock\" } ] }";
|
||||
string jsonString = "{ \"id\": 42, \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"WireMock\" } ] }";
|
||||
var bodyData = new BodyData
|
||||
{
|
||||
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
||||
@@ -411,7 +414,49 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson)).Equals("{\"x\":\"test /foo_object\"}");
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData!.BodyAsJson)).Equals("{\"x\":\"test /foo_object\"}");
|
||||
}
|
||||
|
||||
[CulturedTheory("en-US")]
|
||||
[InlineData(TransformerType.Handlebars, "{ \"id\": 42 }", "{\"x\":\"test 42\",\"y\":42}")]
|
||||
[InlineData(TransformerType.Scriban, "{ \"id\": 42 }", "{\"x\":\"test 42\",\"y\":42}")]
|
||||
[InlineData(TransformerType.ScribanDotLiquid, "{ \"id\": 42 }", "{\"x\":\"test 42\",\"y\":42}")]
|
||||
[InlineData(TransformerType.Handlebars, "{ \"id\": true }", "{\"x\":\"test True\",\"y\":true}")]
|
||||
[InlineData(TransformerType.Scriban, "{ \"id\": true }", "{\"x\":\"test True\",\"y\":true}")]
|
||||
[InlineData(TransformerType.ScribanDotLiquid, "{ \"id\": true }", "{\"x\":\"test True\",\"y\":true}")]
|
||||
[InlineData(TransformerType.Handlebars, "{ \"id\": 0.005 }", "{\"x\":\"test 0.005\",\"y\":0.005}")]
|
||||
[InlineData(TransformerType.Scriban, "{ \"id\": 0.005 }", "{\"x\":\"test 0.005\",\"y\":0.005}")]
|
||||
[InlineData(TransformerType.ScribanDotLiquid, "{ \"id\": 0.005 }", "{\"x\":\"test 0.005\",\"y\":0.005}")]
|
||||
public async Task Response_ProvideResponse_Transformer_WithBodyAsJson_KeepType(TransformerType transformerType, string jsonString, string expected)
|
||||
{
|
||||
// Assign
|
||||
var culture = CultureInfo.CreateSpecificCulture("en-US");
|
||||
var settings = new WireMockServerSettings
|
||||
{
|
||||
FileSystemHandler = _filesystemHandlerMock.Object,
|
||||
Culture = culture
|
||||
};
|
||||
var jsonSettings = new JsonSerializerSettings
|
||||
{
|
||||
Culture = culture
|
||||
};
|
||||
var bodyData = new BodyData
|
||||
{
|
||||
BodyAsJson = JsonConvert.DeserializeObject(jsonString, jsonSettings),
|
||||
DetectedBodyType = BodyType.Json,
|
||||
Encoding = Encoding.UTF8
|
||||
};
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo_object"), "POST", ClientIp, bodyData);
|
||||
|
||||
var responseBuilder = Response.Create()
|
||||
.WithBodyAsJson(new { x = "test {{request.BodyAsJson.id}}", y = "{{request.BodyAsJson.id}}" })
|
||||
.WithTransformer(transformerType);
|
||||
|
||||
// Act
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
JsonConvert.SerializeObject(response.Message.BodyData!.BodyAsJson).Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -431,7 +476,7 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson).Should().Be("[{\"x\":\"test\"}]");
|
||||
JsonConvert.SerializeObject(response.Message.BodyData!.BodyAsJson).Should().Be("[{\"x\":\"test\"}]");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -452,7 +497,7 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson).Should().Be("[{\"x\":\"test\"}]");
|
||||
JsonConvert.SerializeObject(response.Message.BodyData!.BodyAsJson).Should().Be("[{\"x\":\"test\"}]");
|
||||
}
|
||||
|
||||
//[Theory]
|
||||
@@ -488,15 +533,15 @@ public class ResponseWithTransformerTests
|
||||
[InlineData(TransformerType.Handlebars, "\"a\"", "\"a\"")]
|
||||
[InlineData(TransformerType.Handlebars, "\" \"", "\" \"")]
|
||||
[InlineData(TransformerType.Handlebars, "\"'\"", "\"'\"")]
|
||||
[InlineData(TransformerType.Handlebars, "\"false\"", "false")] // bool is special
|
||||
[InlineData(TransformerType.Handlebars, "\"false\"", "\"false\"")]
|
||||
[InlineData(TransformerType.Handlebars, "false", "false")]
|
||||
[InlineData(TransformerType.Handlebars, "\"true\"", "true")] // bool is special
|
||||
[InlineData(TransformerType.Handlebars, "\"true\"", "\"true\"")]
|
||||
[InlineData(TransformerType.Handlebars, "true", "true")]
|
||||
[InlineData(TransformerType.Handlebars, "\"-42\"", "-42")] // todo
|
||||
[InlineData(TransformerType.Handlebars, "\"-42\"", "\"-42\"")]
|
||||
[InlineData(TransformerType.Handlebars, "-42", "-42")]
|
||||
[InlineData(TransformerType.Handlebars, "\"2147483647\"", "2147483647")] // todo
|
||||
[InlineData(TransformerType.Handlebars, "\"2147483647\"", "\"2147483647\"")]
|
||||
[InlineData(TransformerType.Handlebars, "2147483647", "2147483647")]
|
||||
[InlineData(TransformerType.Handlebars, "\"9223372036854775807\"", "9223372036854775807")] // todo
|
||||
[InlineData(TransformerType.Handlebars, "\"9223372036854775807\"", "\"9223372036854775807\"")]
|
||||
[InlineData(TransformerType.Handlebars, "9223372036854775807", "9223372036854775807")]
|
||||
public async Task Response_ProvideResponse_Transformer_WithBodyAsJson_And_ReplaceNodeOptionsKeep(TransformerType transformerType, string value, string expected)
|
||||
{
|
||||
@@ -511,50 +556,13 @@ public class ResponseWithTransformerTests
|
||||
|
||||
var responseBuilder = Response.Create()
|
||||
.WithBodyAsJson(new { text = "{{request.bodyAsJson.x}}" })
|
||||
.WithTransformer(transformerType, false, ReplaceNodeOptions.None);
|
||||
.WithTransformer(transformerType, false, ReplaceNodeOptions.Evaluate);
|
||||
|
||||
// Act
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson).Should().Be($"{{\"text\":{expected}}}");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(TransformerType.Handlebars, "\"\"", "\"\"")]
|
||||
[InlineData(TransformerType.Handlebars, "\"a\"", "\"a\"")]
|
||||
[InlineData(TransformerType.Handlebars, "\" \"", "\" \"")]
|
||||
[InlineData(TransformerType.Handlebars, "\"'\"", "\"'\"")]
|
||||
[InlineData(TransformerType.Handlebars, "\"false\"", "false")] // bool is special
|
||||
[InlineData(TransformerType.Handlebars, "false", "false")]
|
||||
[InlineData(TransformerType.Handlebars, "\"true\"", "true")] // bool is special
|
||||
[InlineData(TransformerType.Handlebars, "true", "true")]
|
||||
[InlineData(TransformerType.Handlebars, "\"-42\"", "\"-42\"")]
|
||||
[InlineData(TransformerType.Handlebars, "-42", "\"-42\"")]
|
||||
[InlineData(TransformerType.Handlebars, "\"2147483647\"", "\"2147483647\"")]
|
||||
[InlineData(TransformerType.Handlebars, "2147483647", "\"2147483647\"")]
|
||||
[InlineData(TransformerType.Handlebars, "\"9223372036854775807\"", "\"9223372036854775807\"")]
|
||||
[InlineData(TransformerType.Handlebars, "9223372036854775807", "\"9223372036854775807\"")]
|
||||
public async Task Response_ProvideResponse_Transformer_WithBodyAsJsonWithExtraQuotes_AlwaysMakesString(TransformerType transformerType, string value, string expected)
|
||||
{
|
||||
string jsonString = $"{{ \"x\": {value} }}";
|
||||
var bodyData = new BodyData
|
||||
{
|
||||
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
||||
DetectedBodyType = BodyType.Json,
|
||||
Encoding = Encoding.UTF8
|
||||
};
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo_object"), "POST", ClientIp, bodyData);
|
||||
|
||||
var responseBuilder = Response.Create()
|
||||
.WithBodyAsJson(new { text = "\"{{request.bodyAsJson.x}}\"" })
|
||||
.WithTransformer(transformerType);
|
||||
|
||||
// Act
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson).Should().Be($"{{\"text\":{expected}}}");
|
||||
JsonConvert.SerializeObject(response.Message.BodyData!.BodyAsJson).Should().Be($"{{\"text\":{expected}}}");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -581,7 +589,7 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson)).Equals("[\"first\",\"/foo_array\",\"test 1\",\"test 2\",\"last\"]");
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData!.BodyAsJson)).Equals("[\"first\",\"/foo_array\",\"test 1\",\"test 2\",\"last\"]");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -598,7 +606,7 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Check.That(response.Message.BodyData.BodyAsFile).Equals(@"c:\1\test.xml");
|
||||
Check.That(response.Message.BodyData!.BodyAsFile).Equals(@"c:\1\test.xml");
|
||||
}
|
||||
|
||||
[Theory(Skip = @"Does not work in Scriban --> c:\\[""1""]\\test.xml")]
|
||||
@@ -617,7 +625,7 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Check.That(response.Message.BodyData.BodyAsFile).Equals(@"c:\1\test.xml");
|
||||
Check.That(response.Message.BodyData!.BodyAsFile).Equals(@"c:\1\test.xml");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -642,7 +650,7 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Check.That(response.Message.BodyData.BodyAsFile).Equals(@"c:\1\test.xml");
|
||||
Check.That(response.Message.BodyData!.BodyAsFile).Equals(@"c:\1\test.xml");
|
||||
Check.That(response.Message.BodyData.DetectedBodyType).Equals(BodyType.String);
|
||||
Check.That(response.Message.BodyData!.BodyAsString).Equals("<xml MyUniqueNumber=\"1\"></xml>");
|
||||
}
|
||||
@@ -671,14 +679,15 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson)).Equals("\"test\"");
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData!.BodyAsJson)).Equals("\"test\"");
|
||||
}
|
||||
|
||||
[Fact(Skip = "todo...")]
|
||||
//[Fact]
|
||||
public async Task Response_ProvideResponse_Handlebars_WithBodyAsJson_ResultAsTemplatedString()
|
||||
{
|
||||
// Assign
|
||||
string jsonString = "{ \"name\": \"WireMock\" }";
|
||||
string jsonString = "{ \"name\": \"WireMock\", \"id\": 12345 }";
|
||||
var bodyData = new BodyData
|
||||
{
|
||||
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
||||
@@ -688,14 +697,14 @@ public class ResponseWithTransformerTests
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo_object"), "POST", ClientIp, bodyData);
|
||||
|
||||
var responseBuilder = Response.Create()
|
||||
.WithBodyAsJson("{{{request.BodyAsJson}}}")
|
||||
.WithBodyAsJson("{{{request.BodyAsJson.name}}}")
|
||||
.WithTransformer();
|
||||
|
||||
// Act
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson)).Equals("{\"name\":\"WireMock\"}");
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData!.BodyAsJson)).Equals("{\"name\":\"WireMock\"}");
|
||||
}
|
||||
|
||||
[Theory(Skip = "{{{ }}} Does not work in Scriban")]
|
||||
@@ -721,7 +730,7 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson)).Equals("{\"name\":\"WireMock\"}");
|
||||
Check.That(JsonConvert.SerializeObject(response.Message.BodyData!.BodyAsJson)).Equals("{\"name\":\"WireMock\"}");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -749,7 +758,7 @@ public class ResponseWithTransformerTests
|
||||
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
response.Message.BodyData.BodyAsString.Should().Be(text);
|
||||
response.Message.BodyData!.BodyAsString.Should().Be(text);
|
||||
response.Message.BodyData.Encoding.Should().Be(enc);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,59 @@
|
||||
using System;
|
||||
using FluentAssertions;
|
||||
using HandlebarsDotNet;
|
||||
using Moq;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Transformers.Handlebars;
|
||||
using Xunit;
|
||||
|
||||
namespace WireMock.Net.Tests.Transformers.Handlebars
|
||||
namespace WireMock.Net.Tests.Transformers.Handlebars;
|
||||
|
||||
public class HandlebarsContextFactoryTests
|
||||
{
|
||||
public class HandlebarsContextFactoryTests
|
||||
private readonly Mock<IFileSystemHandler> _fileSystemHandlerMock = new();
|
||||
|
||||
[Fact]
|
||||
public void Create_WithNullAction_DoesNotInvokeAction()
|
||||
{
|
||||
private readonly Mock<IFileSystemHandler> _fileSystemHandlerMock = new Mock<IFileSystemHandler>();
|
||||
|
||||
[Fact]
|
||||
public void Create_WithNullAction_DoesNotInvokeAction()
|
||||
// Arrange
|
||||
var settings = new WireMockServerSettings
|
||||
{
|
||||
// Arrange
|
||||
var sut = new HandlebarsContextFactory(_fileSystemHandlerMock.Object, null);
|
||||
FileSystemHandler = _fileSystemHandlerMock.Object
|
||||
};
|
||||
var sut = new HandlebarsContextFactory(settings);
|
||||
|
||||
// Act
|
||||
var result = sut.Create();
|
||||
// Act
|
||||
var result = sut.Create();
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
}
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithAction_InvokesAction()
|
||||
[Fact]
|
||||
public void Create_WithAction_InvokesAction()
|
||||
{
|
||||
// Arrange
|
||||
int num = 0;
|
||||
var settings = new WireMockServerSettings
|
||||
{
|
||||
// Arrange
|
||||
int num = 0;
|
||||
Action<IHandlebars, IFileSystemHandler> action = (ctx, fs) =>
|
||||
FileSystemHandler = _fileSystemHandlerMock.Object,
|
||||
HandlebarsRegistrationCallback = (ctx, fs) =>
|
||||
{
|
||||
ctx.Should().NotBeNull();
|
||||
fs.Should().NotBeNull();
|
||||
|
||||
num++;
|
||||
};
|
||||
var sut = new HandlebarsContextFactory(_fileSystemHandlerMock.Object, action);
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = sut.Create();
|
||||
var sut = new HandlebarsContextFactory(settings);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
// Act
|
||||
var result = sut.Create();
|
||||
|
||||
// Verify
|
||||
num.Should().Be(1);
|
||||
}
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
|
||||
// Verify
|
||||
num.Should().Be(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,10 @@
|
||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'net452' or '$(TargetFramework)' == 'net461'">
|
||||
<DefineConstants>NETFRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\src\WireMock.Net.FluentAssertions\WireMock.Net.FluentAssertions.csproj" />
|
||||
@@ -35,8 +39,10 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="CultureAwareTesting.xUnit" Version="0.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.core" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
Reference in New Issue
Block a user