From c35315e6104693ac5e6439febdfe7229031ced3c Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 19 Jan 2021 21:11:33 +0100 Subject: [PATCH] Refactor Transformer (add Scriban) (#562) --- Directory.Build.props | 2 +- .../MainApp.cs | 3 +- .../Admin/Mappings/ResponseModel.cs | 8 +- .../Types/TransformerType.cs | 23 + .../ITransformResponseBuilder.cs | 14 +- src/WireMock.Net/ResponseBuilders/Response.cs | 39 +- .../Serialization/MappingConverter.cs | 2 + .../Server/WireMockServer.Admin.cs | 6 +- .../{ => Handlebars}/HandlebarsContext.cs | 10 +- .../HandlebarsContextFactory.cs | 13 +- .../HandlebarsFile.cs} | 2 +- .../HandlebarsJsonPath.cs} | 2 +- .../HandlebarsLinq.cs} | 2 +- .../HandlebarsRandom.cs} | 2 +- .../HandlebarsRegex.cs} | 2 +- .../HandlebarsXPath.cs} | 2 +- .../HandlebarsXeger.cs} | 2 +- .../Handlebars/IHandlebarsContext.cs | 9 + .../WireMockHandlebarsHelpers.cs | 2 +- .../Transformers/IHandlebarsContext.cs | 12 - .../Transformers/IHandlebarsContextFactory.cs | 7 - src/WireMock.Net/Transformers/ITransformer.cs | 7 + .../Transformers/ITransformerContext.cs | 11 + .../ITransformerContextFactory.cs | 7 + .../Transformers/Scriban/ScribanContext.cs | 27 + .../Scriban/ScribanContextFactory.cs | 26 + .../Scriban/WireMockListAccessor.cs | 55 + .../Scriban/WireMockTemplateContext.cs | 19 + ...seMessageTransformer.cs => Transformer.cs} | 460 ++++---- src/WireMock.Net/WireMock.Net.csproj | 13 + .../ResponseBuilders/ResponseWithBodyTests.cs | 14 +- .../ResponseWithCallbackTests.cs | 13 + .../ResponseWithHandlebarsHelpersTests.cs | 14 +- .../ResponseWithHandlebarsJsonPathTests.cs | 43 +- .../ResponseWithHandlebarsLinqTests.cs | 11 + .../ResponseWithHandlebarsRandomTests.cs | 14 +- .../ResponseWithHandlebarsRegexTests.cs | 14 +- .../ResponseWithHandlebarsXPathTests.cs | 14 +- .../ResponseWithHandlebarsXegerTests.cs | 13 +- .../ResponseWithScribanTests.cs | 74 ++ ...sts.cs => ResponseWithTransformerTests.cs} | 1015 ++++++++++------- .../HandlebarsContextFactoryTests.cs | 104 +- .../Scriban/ScribanContextFactoryTests.cs | 40 + 43 files changed, 1405 insertions(+), 767 deletions(-) create mode 100644 src/WireMock.Net.Abstractions/Types/TransformerType.cs rename src/WireMock.Net/Transformers/{ => Handlebars}/HandlebarsContext.cs (52%) rename src/WireMock.Net/Transformers/{ => Handlebars}/HandlebarsContextFactory.cs (59%) rename src/WireMock.Net/Transformers/{HandleBarsFile.cs => Handlebars/HandlebarsFile.cs} (97%) rename src/WireMock.Net/Transformers/{HandleBarsJsonPath.cs => Handlebars/HandlebarsJsonPath.cs} (98%) rename src/WireMock.Net/Transformers/{HandleBarsLinq.cs => Handlebars/HandlebarsLinq.cs} (98%) rename src/WireMock.Net/Transformers/{HandleBarsRandom.cs => Handlebars/HandlebarsRandom.cs} (98%) rename src/WireMock.Net/Transformers/{HandleBarsRegex.cs => Handlebars/HandlebarsRegex.cs} (98%) rename src/WireMock.Net/Transformers/{HandleBarsXPath.cs => Handlebars/HandlebarsXPath.cs} (98%) rename src/WireMock.Net/Transformers/{HandleBarsXeger.cs => Handlebars/HandlebarsXeger.cs} (96%) create mode 100644 src/WireMock.Net/Transformers/Handlebars/IHandlebarsContext.cs rename src/WireMock.Net/Transformers/{ => Handlebars}/WireMockHandlebarsHelpers.cs (95%) delete mode 100644 src/WireMock.Net/Transformers/IHandlebarsContext.cs delete mode 100644 src/WireMock.Net/Transformers/IHandlebarsContextFactory.cs create mode 100644 src/WireMock.Net/Transformers/ITransformer.cs create mode 100644 src/WireMock.Net/Transformers/ITransformerContext.cs create mode 100644 src/WireMock.Net/Transformers/ITransformerContextFactory.cs create mode 100644 src/WireMock.Net/Transformers/Scriban/ScribanContext.cs create mode 100644 src/WireMock.Net/Transformers/Scriban/ScribanContextFactory.cs create mode 100644 src/WireMock.Net/Transformers/Scriban/WireMockListAccessor.cs create mode 100644 src/WireMock.Net/Transformers/Scriban/WireMockTemplateContext.cs rename src/WireMock.Net/Transformers/{ResponseMessageTransformer.cs => Transformer.cs} (65%) create mode 100644 test/WireMock.Net.Tests/ResponseBuilders/ResponseWithScribanTests.cs rename test/WireMock.Net.Tests/ResponseBuilders/{ResponseWithHandlebarsTests.cs => ResponseWithTransformerTests.cs} (57%) rename test/WireMock.Net.Tests/Transformers/{ => Handlebars}/HandlebarsContextFactoryTests.cs (89%) create mode 100644 test/WireMock.Net.Tests/Transformers/Scriban/ScribanContextFactoryTests.cs diff --git a/Directory.Build.props b/Directory.Build.props index 1275b6d3..2d73223e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ - 1.4.0 + 1.4.1 See CHANGELOG.md https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/WireMock.Net-Logo.png https://github.com/WireMock-Net/WireMock.Net diff --git a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs index 870a46ca..78f00afb 100644 --- a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs +++ b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs @@ -13,6 +13,7 @@ using WireMock.Server; using WireMock.Settings; using WireMock.Util; using System.Threading.Tasks; +using WireMock.Types; namespace WireMock.Net.ConsoleApplication { @@ -346,7 +347,7 @@ namespace WireMock.Net.ConsoleApplication .WithHeader("Transformed-Postman-Token", "token is {{request.headers.Postman-Token}}") .WithHeader("xyz_{{request.headers.Postman-Token}}", "token is {{request.headers.Postman-Token}}") .WithBody(@"{""msg"": ""Hello world CATCH-ALL on /*, {{request.path}}, add={{Math.Add request.query.start.[0] 42}} bykey={{request.query.start}}, bykey={{request.query.stop}}, byidx0={{request.query.stop.[0]}}, byidx1={{request.query.stop.[1]}}"" }") - .WithTransformer() + .WithTransformer(TransformerType.Handlebars) .WithDelay(TimeSpan.FromMilliseconds(100)) ); diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs index 1c73ff55..28035a8d 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/ResponseModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using WireMock.Types; namespace WireMock.Admin.Mappings { @@ -53,10 +54,15 @@ namespace WireMock.Admin.Mappings public EncodingModel BodyEncoding { get; set; } /// - /// Use Handlebars transformer. + /// Use ResponseMessage Transformer. /// public bool? UseTransformer { get; set; } + /// + /// Gets the type of the transformer. + /// + public string TransformerType { get; set; } + /// /// Use the Handlerbars transformer for the content from the referenced BodyAsFile. /// diff --git a/src/WireMock.Net.Abstractions/Types/TransformerType.cs b/src/WireMock.Net.Abstractions/Types/TransformerType.cs new file mode 100644 index 00000000..5d7015e1 --- /dev/null +++ b/src/WireMock.Net.Abstractions/Types/TransformerType.cs @@ -0,0 +1,23 @@ +namespace WireMock.Types +{ + /// + /// The ResponseMessage Transformers + /// + public enum TransformerType + { + /// + /// https://github.com/Handlebars-Net/Handlebars.Net + /// + Handlebars, + + /// + /// https://github.com/scriban/scriban : default + /// + Scriban, + + /// + /// https://github.com/scriban/scriban : DotLiquid + /// + ScribanDotLiquid + } +} \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs index 1efb2e41..e1cfcaf0 100644 --- a/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs @@ -1,4 +1,6 @@ -namespace WireMock.ResponseBuilders +using WireMock.Types; + +namespace WireMock.ResponseBuilders { /// /// The TransformResponseBuilder interface. @@ -6,11 +8,19 @@ public interface ITransformResponseBuilder : IDelayResponseBuilder { /// - /// The with transformer. + /// Use the Handlebars.Net ResponseMessage transformer. /// /// /// The . /// IResponseBuilder WithTransformer(bool transformContentFromBodyAsFile = false); + + /// + /// Use a specific ResponseMessage transformer. + /// + /// + /// The . + /// + IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/Response.cs b/src/WireMock.Net/ResponseBuilders/Response.cs index b999bd55..615f3f7a 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.cs @@ -11,6 +11,8 @@ using WireMock.Proxy; using WireMock.ResponseProviders; using WireMock.Settings; using WireMock.Transformers; +using WireMock.Transformers.Handlebars; +using WireMock.Transformers.Scriban; using WireMock.Types; using WireMock.Util; using WireMock.Validation; @@ -32,6 +34,11 @@ namespace WireMock.ResponseBuilders /// public bool UseTransformer { get; private set; } + /// + /// Gets the type of the transformer. + /// + public TransformerType TransformerType { get; private set; } + /// /// Gets a value indicating whether to use the Handlerbars transformer for the content from the referenced BodyAsFile. /// @@ -282,6 +289,16 @@ namespace WireMock.ResponseBuilders public IResponseBuilder WithTransformer(bool transformContentFromBodyAsFile = false) { UseTransformer = true; + TransformerType = TransformerType.Handlebars; + UseTransformerForBodyAsFile = transformContentFromBodyAsFile; + return this; + } + + /// + public IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false) + { + UseTransformer = true; + TransformerType = transformerType; UseTransformerForBodyAsFile = transformContentFromBodyAsFile; return this; } @@ -328,7 +345,7 @@ namespace WireMock.ResponseBuilders var proxyHelper = new ProxyHelper(settings); - var (proxyResponseMessage, mapping) = await proxyHelper.SendAsync( + var (proxyResponseMessage, _) = await proxyHelper.SendAsync( ProxyAndRecordSettings, _httpClientForProxy, requestMessage, @@ -369,8 +386,24 @@ namespace WireMock.ResponseBuilders if (UseTransformer) { - var factory = new HandlebarsContextFactory(settings.FileSystemHandler, settings.HandlebarsRegistrationCallback); - var responseMessageTransformer = new ResponseMessageTransformer(factory); + ITransformer responseMessageTransformer; + switch (TransformerType) + { + case TransformerType.Handlebars: + var factoryHandlebars = new HandlebarsContextFactory(settings.FileSystemHandler, settings.HandlebarsRegistrationCallback); + responseMessageTransformer = new Transformer(factoryHandlebars); + break; + + case TransformerType.Scriban: + case TransformerType.ScribanDotLiquid: + var factoryDotLiquid = new ScribanContextFactory(settings.FileSystemHandler, TransformerType); + responseMessageTransformer = new Transformer(factoryDotLiquid); + break; + + default: + throw new NotImplementedException($"TransformerType '{TransformerType}' is not supported."); + } + return responseMessageTransformer.Transform(requestMessage, responseMessage, UseTransformerForBodyAsFile); } diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs index 6e4167f9..844885d2 100644 --- a/src/WireMock.Net/Serialization/MappingConverter.cs +++ b/src/WireMock.Net/Serialization/MappingConverter.cs @@ -113,6 +113,7 @@ namespace WireMock.Serialization mappingModel.Response.BodyAsFile = null; mappingModel.Response.BodyAsFileIsCached = null; mappingModel.Response.UseTransformer = null; + mappingModel.Response.TransformerType = null; mappingModel.Response.UseTransformerForBodyAsFile = null; mappingModel.Response.BodyEncoding = null; mappingModel.Response.ProxyUrl = response.ProxyAndRecordSettings.Url; @@ -133,6 +134,7 @@ namespace WireMock.Serialization if (response.UseTransformer) { mappingModel.Response.UseTransformer = response.UseTransformer; + mappingModel.Response.TransformerType = response.TransformerType.ToString(); } if (response.UseTransformerForBodyAsFile) diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs index 80b91e01..e5f9b403 100644 --- a/src/WireMock.Net/Server/WireMockServer.Admin.cs +++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs @@ -770,7 +770,11 @@ namespace WireMock.Server if (responseModel.UseTransformer == true) { - responseBuilder = responseBuilder.WithTransformer(responseModel.UseTransformerForBodyAsFile == true); + if (!Enum.TryParse(responseModel.TransformerType, out var transformerType)) + { + transformerType = TransformerType.Handlebars; + } + responseBuilder = responseBuilder.WithTransformer(transformerType, responseModel.UseTransformerForBodyAsFile == true); } if (!string.IsNullOrEmpty(responseModel.ProxyUrl)) diff --git a/src/WireMock.Net/Transformers/HandlebarsContext.cs b/src/WireMock.Net/Transformers/Handlebars/HandlebarsContext.cs similarity index 52% rename from src/WireMock.Net/Transformers/HandlebarsContext.cs rename to src/WireMock.Net/Transformers/Handlebars/HandlebarsContext.cs index d0187ebe..191a72c6 100644 --- a/src/WireMock.Net/Transformers/HandlebarsContext.cs +++ b/src/WireMock.Net/Transformers/Handlebars/HandlebarsContext.cs @@ -1,11 +1,19 @@ using HandlebarsDotNet; using WireMock.Handlers; -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { internal class HandlebarsContext : IHandlebarsContext { public IHandlebars Handlebars { get; set; } + public IFileSystemHandler FileSystemHandler { get; set; } + + public string ParseAndRender(string text, object model) + { + var template = Handlebars.Compile(text); + + return template(model); + } } } \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/HandlebarsContextFactory.cs b/src/WireMock.Net/Transformers/Handlebars/HandlebarsContextFactory.cs similarity index 59% rename from src/WireMock.Net/Transformers/HandlebarsContextFactory.cs rename to src/WireMock.Net/Transformers/Handlebars/HandlebarsContextFactory.cs index 751c26ef..4bd98e42 100644 --- a/src/WireMock.Net/Transformers/HandlebarsContextFactory.cs +++ b/src/WireMock.Net/Transformers/Handlebars/HandlebarsContextFactory.cs @@ -1,10 +1,11 @@ using System; using HandlebarsDotNet; +using JetBrains.Annotations; using WireMock.Handlers; -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { - internal class HandlebarsContextFactory : IHandlebarsContextFactory + internal class HandlebarsContextFactory : ITransformerContextFactory { private static readonly HandlebarsConfiguration HandlebarsConfiguration = new HandlebarsConfiguration { @@ -14,15 +15,15 @@ namespace WireMock.Transformers private readonly IFileSystemHandler _fileSystemHandler; private readonly Action _action; - public HandlebarsContextFactory(IFileSystemHandler fileSystemHandler, Action action) + public HandlebarsContextFactory([NotNull] IFileSystemHandler fileSystemHandler, [CanBeNull] Action action) { - _fileSystemHandler = fileSystemHandler; + _fileSystemHandler = fileSystemHandler ?? throw new ArgumentNullException(nameof(fileSystemHandler)); _action = action; } - public IHandlebarsContext Create() + public ITransformerContext Create() { - var handlebars = Handlebars.Create(HandlebarsConfiguration); + var handlebars = HandlebarsDotNet.Handlebars.Create(HandlebarsConfiguration); WireMockHandlebarsHelpers.Register(handlebars, _fileSystemHandler); diff --git a/src/WireMock.Net/Transformers/HandleBarsFile.cs b/src/WireMock.Net/Transformers/Handlebars/HandlebarsFile.cs similarity index 97% rename from src/WireMock.Net/Transformers/HandleBarsFile.cs rename to src/WireMock.Net/Transformers/Handlebars/HandlebarsFile.cs index e5bbf8e2..42d7c296 100644 --- a/src/WireMock.Net/Transformers/HandleBarsFile.cs +++ b/src/WireMock.Net/Transformers/Handlebars/HandlebarsFile.cs @@ -3,7 +3,7 @@ using System; using WireMock.Handlers; using WireMock.Validation; -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { internal static class HandlebarsFile { diff --git a/src/WireMock.Net/Transformers/HandleBarsJsonPath.cs b/src/WireMock.Net/Transformers/Handlebars/HandlebarsJsonPath.cs similarity index 98% rename from src/WireMock.Net/Transformers/HandleBarsJsonPath.cs rename to src/WireMock.Net/Transformers/Handlebars/HandlebarsJsonPath.cs index b976b62e..c016f374 100644 --- a/src/WireMock.Net/Transformers/HandleBarsJsonPath.cs +++ b/src/WireMock.Net/Transformers/Handlebars/HandlebarsJsonPath.cs @@ -7,7 +7,7 @@ using System.Linq; using WireMock.Util; using WireMock.Validation; -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { internal static class HandlebarsJsonPath { diff --git a/src/WireMock.Net/Transformers/HandleBarsLinq.cs b/src/WireMock.Net/Transformers/Handlebars/HandlebarsLinq.cs similarity index 98% rename from src/WireMock.Net/Transformers/HandleBarsLinq.cs rename to src/WireMock.Net/Transformers/Handlebars/HandlebarsLinq.cs index be5a473f..946d1913 100644 --- a/src/WireMock.Net/Transformers/HandleBarsLinq.cs +++ b/src/WireMock.Net/Transformers/Handlebars/HandlebarsLinq.cs @@ -7,7 +7,7 @@ using Newtonsoft.Json.Linq; using WireMock.Util; using WireMock.Validation; -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { internal static class HandlebarsLinq { diff --git a/src/WireMock.Net/Transformers/HandleBarsRandom.cs b/src/WireMock.Net/Transformers/Handlebars/HandlebarsRandom.cs similarity index 98% rename from src/WireMock.Net/Transformers/HandleBarsRandom.cs rename to src/WireMock.Net/Transformers/Handlebars/HandlebarsRandom.cs index 4bc11ba7..9f73b849 100644 --- a/src/WireMock.Net/Transformers/HandleBarsRandom.cs +++ b/src/WireMock.Net/Transformers/Handlebars/HandlebarsRandom.cs @@ -9,7 +9,7 @@ using RandomDataGenerator.FieldOptions; using RandomDataGenerator.Randomizers; using WireMock.Validation; -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { internal static class HandlebarsRandom { diff --git a/src/WireMock.Net/Transformers/HandleBarsRegex.cs b/src/WireMock.Net/Transformers/Handlebars/HandlebarsRegex.cs similarity index 98% rename from src/WireMock.Net/Transformers/HandleBarsRegex.cs rename to src/WireMock.Net/Transformers/Handlebars/HandlebarsRegex.cs index 490ceed2..5a53a8c2 100644 --- a/src/WireMock.Net/Transformers/HandleBarsRegex.cs +++ b/src/WireMock.Net/Transformers/Handlebars/HandlebarsRegex.cs @@ -5,7 +5,7 @@ using HandlebarsDotNet; using WireMock.Util; using WireMock.Validation; -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { internal static class HandlebarsRegex { diff --git a/src/WireMock.Net/Transformers/HandleBarsXPath.cs b/src/WireMock.Net/Transformers/Handlebars/HandlebarsXPath.cs similarity index 98% rename from src/WireMock.Net/Transformers/HandleBarsXPath.cs rename to src/WireMock.Net/Transformers/Handlebars/HandlebarsXPath.cs index 48ba898e..1e0ee0c1 100644 --- a/src/WireMock.Net/Transformers/HandleBarsXPath.cs +++ b/src/WireMock.Net/Transformers/Handlebars/HandlebarsXPath.cs @@ -8,7 +8,7 @@ using WireMock.Validation; using Wmhelp.XPath2; #endif -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { internal static class HandlebarsXPath { diff --git a/src/WireMock.Net/Transformers/HandleBarsXeger.cs b/src/WireMock.Net/Transformers/Handlebars/HandlebarsXeger.cs similarity index 96% rename from src/WireMock.Net/Transformers/HandleBarsXeger.cs rename to src/WireMock.Net/Transformers/Handlebars/HandlebarsXeger.cs index 92786aab..94b58f80 100644 --- a/src/WireMock.Net/Transformers/HandleBarsXeger.cs +++ b/src/WireMock.Net/Transformers/Handlebars/HandlebarsXeger.cs @@ -3,7 +3,7 @@ using Fare; using HandlebarsDotNet; using WireMock.Validation; -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { internal static class HandlebarsXeger { diff --git a/src/WireMock.Net/Transformers/Handlebars/IHandlebarsContext.cs b/src/WireMock.Net/Transformers/Handlebars/IHandlebarsContext.cs new file mode 100644 index 00000000..e96b48bd --- /dev/null +++ b/src/WireMock.Net/Transformers/Handlebars/IHandlebarsContext.cs @@ -0,0 +1,9 @@ +using HandlebarsDotNet; + +namespace WireMock.Transformers.Handlebars +{ + interface IHandlebarsContext : ITransformerContext + { + IHandlebars Handlebars { get; set; } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/WireMockHandlebarsHelpers.cs b/src/WireMock.Net/Transformers/Handlebars/WireMockHandlebarsHelpers.cs similarity index 95% rename from src/WireMock.Net/Transformers/WireMockHandlebarsHelpers.cs rename to src/WireMock.Net/Transformers/Handlebars/WireMockHandlebarsHelpers.cs index 0ecce91d..70b5a319 100644 --- a/src/WireMock.Net/Transformers/WireMockHandlebarsHelpers.cs +++ b/src/WireMock.Net/Transformers/Handlebars/WireMockHandlebarsHelpers.cs @@ -2,7 +2,7 @@ using HandlebarsDotNet.Helpers; using WireMock.Handlers; -namespace WireMock.Transformers +namespace WireMock.Transformers.Handlebars { internal static class WireMockHandlebarsHelpers { diff --git a/src/WireMock.Net/Transformers/IHandlebarsContext.cs b/src/WireMock.Net/Transformers/IHandlebarsContext.cs deleted file mode 100644 index a551b225..00000000 --- a/src/WireMock.Net/Transformers/IHandlebarsContext.cs +++ /dev/null @@ -1,12 +0,0 @@ -using HandlebarsDotNet; -using WireMock.Handlers; - -namespace WireMock.Transformers -{ - interface IHandlebarsContext - { - IHandlebars Handlebars { get; set; } - - IFileSystemHandler FileSystemHandler { get; set; } - } -} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/IHandlebarsContextFactory.cs b/src/WireMock.Net/Transformers/IHandlebarsContextFactory.cs deleted file mode 100644 index 73b730ff..00000000 --- a/src/WireMock.Net/Transformers/IHandlebarsContextFactory.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace WireMock.Transformers -{ - interface IHandlebarsContextFactory - { - IHandlebarsContext Create(); - } -} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/ITransformer.cs b/src/WireMock.Net/Transformers/ITransformer.cs new file mode 100644 index 00000000..e6e4d540 --- /dev/null +++ b/src/WireMock.Net/Transformers/ITransformer.cs @@ -0,0 +1,7 @@ +namespace WireMock.Transformers +{ + interface ITransformer + { + ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original, bool useTransformerForBodyAsFile); + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/ITransformerContext.cs b/src/WireMock.Net/Transformers/ITransformerContext.cs new file mode 100644 index 00000000..1ddf0816 --- /dev/null +++ b/src/WireMock.Net/Transformers/ITransformerContext.cs @@ -0,0 +1,11 @@ +using WireMock.Handlers; + +namespace WireMock.Transformers +{ + interface ITransformerContext + { + IFileSystemHandler FileSystemHandler { get; set; } + + string ParseAndRender(string text, object model); + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/ITransformerContextFactory.cs b/src/WireMock.Net/Transformers/ITransformerContextFactory.cs new file mode 100644 index 00000000..dd345be2 --- /dev/null +++ b/src/WireMock.Net/Transformers/ITransformerContextFactory.cs @@ -0,0 +1,7 @@ +namespace WireMock.Transformers +{ + interface ITransformerContextFactory + { + ITransformerContext Create(); + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/Scriban/ScribanContext.cs b/src/WireMock.Net/Transformers/Scriban/ScribanContext.cs new file mode 100644 index 00000000..5f347fcf --- /dev/null +++ b/src/WireMock.Net/Transformers/Scriban/ScribanContext.cs @@ -0,0 +1,27 @@ +using System; +using Scriban; +using WireMock.Handlers; +using WireMock.Types; + +namespace WireMock.Transformers.Scriban +{ + internal class ScribanContext : ITransformerContext + { + private readonly TransformerType _transformerType; + + public IFileSystemHandler FileSystemHandler { get; set; } + + public ScribanContext(IFileSystemHandler fileSystemHandler, TransformerType transformerType) + { + FileSystemHandler = fileSystemHandler ?? throw new ArgumentNullException(nameof(fileSystemHandler)); + _transformerType = transformerType; + } + + 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); + } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/Scriban/ScribanContextFactory.cs b/src/WireMock.Net/Transformers/Scriban/ScribanContextFactory.cs new file mode 100644 index 00000000..bc5c79d2 --- /dev/null +++ b/src/WireMock.Net/Transformers/Scriban/ScribanContextFactory.cs @@ -0,0 +1,26 @@ +using WireMock.Handlers; +using WireMock.Types; +using WireMock.Validation; + +namespace WireMock.Transformers.Scriban +{ + internal class ScribanContextFactory : ITransformerContextFactory + { + private readonly IFileSystemHandler _fileSystemHandler; + private readonly TransformerType _transformerType; + + public ScribanContextFactory(IFileSystemHandler fileSystemHandler, TransformerType transformerType) + { + Check.NotNull(fileSystemHandler, nameof(fileSystemHandler)); + Check.Condition(transformerType, t => t == TransformerType.Scriban || t == TransformerType.ScribanDotLiquid, nameof(transformerType)); + + _fileSystemHandler = fileSystemHandler; + _transformerType = transformerType; + } + + public ITransformerContext Create() + { + return new ScribanContext(_fileSystemHandler, _transformerType); + } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/Scriban/WireMockListAccessor.cs b/src/WireMock.Net/Transformers/Scriban/WireMockListAccessor.cs new file mode 100644 index 00000000..08af878e --- /dev/null +++ b/src/WireMock.Net/Transformers/Scriban/WireMockListAccessor.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using Scriban; +using Scriban.Parsing; +using Scriban.Runtime; + +namespace WireMock.Transformers.Scriban +{ + internal class WireMockListAccessor : IListAccessor, IObjectAccessor + { + #region IListAccessor + public int GetLength(TemplateContext context, SourceSpan span, object target) + { + throw new NotImplementedException(); + } + + public object GetValue(TemplateContext context, SourceSpan span, object target, int index) + { + return target.ToString(); + } + + public void SetValue(TemplateContext context, SourceSpan span, object target, int index, object value) + { + throw new NotImplementedException(); + } + #endregion + + #region IObjectAccessor + public int GetMemberCount(TemplateContext context, SourceSpan span, object target) + { + throw new NotImplementedException(); + } + + public IEnumerable GetMembers(TemplateContext context, SourceSpan span, object target) + { + throw new NotImplementedException(); + } + + public bool HasMember(TemplateContext context, SourceSpan span, object target, string member) + { + throw new NotImplementedException(); + } + + public bool TryGetValue(TemplateContext context, SourceSpan span, object target, string member, out object value) + { + throw new NotImplementedException(); + } + + public bool TrySetValue(TemplateContext context, SourceSpan span, object target, string member, object value) + { + throw new NotImplementedException(); + } + #endregion + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/Scriban/WireMockTemplateContext.cs b/src/WireMock.Net/Transformers/Scriban/WireMockTemplateContext.cs new file mode 100644 index 00000000..817a88c5 --- /dev/null +++ b/src/WireMock.Net/Transformers/Scriban/WireMockTemplateContext.cs @@ -0,0 +1,19 @@ +using Scriban; +using Scriban.Runtime; +using WireMock.Types; + +namespace WireMock.Transformers.Scriban +{ + internal class WireMockTemplateContext: TemplateContext + { + protected override IObjectAccessor GetMemberAccessorImpl(object target) + { + if (target?.GetType().GetGenericTypeDefinition() == typeof(WireMockList<>)) + { + return new WireMockListAccessor(); + } + + return base.GetMemberAccessorImpl(target); + } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Transformers/ResponseMessageTransformer.cs b/src/WireMock.Net/Transformers/Transformer.cs similarity index 65% rename from src/WireMock.Net/Transformers/ResponseMessageTransformer.cs rename to src/WireMock.Net/Transformers/Transformer.cs index 65aa277a..6fa496f1 100644 --- a/src/WireMock.Net/Transformers/ResponseMessageTransformer.cs +++ b/src/WireMock.Net/Transformers/Transformer.cs @@ -1,235 +1,227 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using HandlebarsDotNet; -using JetBrains.Annotations; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using WireMock.Types; -using WireMock.Util; -using WireMock.Validation; - -namespace WireMock.Transformers -{ - internal class ResponseMessageTransformer - { - private readonly IHandlebarsContextFactory _factory; - - public ResponseMessageTransformer([NotNull] IHandlebarsContextFactory factory) - { - Check.NotNull(factory, nameof(factory)); - - _factory = factory; - } - - public ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original, bool useTransformerForBodyAsFile) - { - var handlebarsContext = _factory.Create(); - - var responseMessage = new ResponseMessage(); - - var template = new { request = requestMessage }; - - switch (original.BodyData?.DetectedBodyType) - { - case BodyType.Json: - TransformBodyAsJson(handlebarsContext.Handlebars, template, original, responseMessage); - break; - - case BodyType.File: - TransformBodyAsFile(handlebarsContext, template, original, responseMessage, useTransformerForBodyAsFile); - break; - - case BodyType.String: - responseMessage.BodyOriginal = original.BodyData.BodyAsString; - TransformBodyAsString(handlebarsContext.Handlebars, template, original, responseMessage); - break; - } - - responseMessage.FaultType = original.FaultType; - responseMessage.FaultPercentage = original.FaultPercentage; - - // Headers - var newHeaders = new Dictionary>(); - foreach (var header in original.Headers) - { - var templateHeaderKey = handlebarsContext.Handlebars.Compile(header.Key); - var templateHeaderValues = header.Value - .Select(handlebarsContext.Handlebars.Compile) - .Select(func => func(template)) - .ToArray(); - - newHeaders.Add(templateHeaderKey(template), new WireMockList(templateHeaderValues)); - } - - responseMessage.Headers = newHeaders; - - switch (original.StatusCode) - { - case int statusCodeAsInteger: - responseMessage.StatusCode = statusCodeAsInteger; - break; - - case string statusCodeAsString: - var templateForStatusCode = handlebarsContext.Handlebars.Compile(statusCodeAsString); - responseMessage.StatusCode = templateForStatusCode(template); - break; - } - - return responseMessage; - } - - private static void TransformBodyAsJson(IHandlebars handlebarsContext, object template, ResponseMessage original, ResponseMessage responseMessage) - { - JToken jToken; - switch (original.BodyData.BodyAsJson) - { - case JObject bodyAsJObject: - jToken = bodyAsJObject.DeepClone(); - WalkNode(handlebarsContext, jToken, template); - break; - - case Array bodyAsArray: - jToken = JArray.FromObject(bodyAsArray); - WalkNode(handlebarsContext, jToken, template); - break; - - case string bodyAsString: - jToken = ReplaceSingleNode(handlebarsContext, bodyAsString, template); - break; - - default: - jToken = JObject.FromObject(original.BodyData.BodyAsJson); - WalkNode(handlebarsContext, jToken, template); - break; - } - - responseMessage.BodyData = new BodyData - { - Encoding = original.BodyData.Encoding, - DetectedBodyType = original.BodyData.DetectedBodyType, - DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, - BodyAsJson = jToken - }; - } - - private static JToken ReplaceSingleNode(IHandlebars handlebarsContext, string stringValue, object context) - { - var templateForStringValue = handlebarsContext.Compile(stringValue); - string transformedString = templateForStringValue(context); - if (!string.Equals(stringValue, transformedString)) - { - const string property = "_"; - JObject dummy = JObject.Parse($"{{ \"{property}\": null }}"); - JToken node = dummy[property]; - - ReplaceNodeValue(node, transformedString); - - return dummy[property]; - } - - return stringValue; - } - - private static void WalkNode(IHandlebars handlebarsContext, JToken node, object context) - { - if (node.Type == JTokenType.Object) - { - // In case of Object, loop all children. Do a ToArray() to avoid `Collection was modified` exceptions. - foreach (JProperty child in node.Children().ToArray()) - { - WalkNode(handlebarsContext, child.Value, context); - } - } - else if (node.Type == JTokenType.Array) - { - // In case of Array, loop all items. Do a ToArray() to avoid `Collection was modified` exceptions. - foreach (JToken child in node.Children().ToArray()) - { - WalkNode(handlebarsContext, child, context); - } - } - else if (node.Type == JTokenType.String) - { - // In case of string, try to transform the value. - string stringValue = node.Value(); - if (string.IsNullOrEmpty(stringValue)) - { - return; - } - - var templateForStringValue = handlebarsContext.Compile(stringValue); - string transformedString = templateForStringValue(context); - if (!string.Equals(stringValue, transformedString)) - { - ReplaceNodeValue(node, transformedString); - } - } - } - - private static void ReplaceNodeValue(JToken node, string stringValue) - { - if (bool.TryParse(stringValue, out bool valueAsBoolean)) - { - node.Replace(valueAsBoolean); - return; - } - - JToken value; - try - { - // Try to convert this string into a JsonObject - value = JToken.Parse(stringValue); - } - catch (JsonException) - { - // Ignore JsonException and just keep string value and convert to JToken - value = stringValue; - } - - node.Replace(value); - } - - private static void TransformBodyAsString(IHandlebars handlebarsContext, object template, ResponseMessage original, ResponseMessage responseMessage) - { - var templateBodyAsString = handlebarsContext.Compile(original.BodyData.BodyAsString); - - responseMessage.BodyData = new BodyData - { - Encoding = original.BodyData.Encoding, - DetectedBodyType = original.BodyData.DetectedBodyType, - DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, - BodyAsString = templateBodyAsString(template) - }; - } - - private void TransformBodyAsFile(IHandlebarsContext handlebarsContext, object template, ResponseMessage original, ResponseMessage responseMessage, bool useTransformerForBodyAsFile) - { - var templateBodyAsFile = handlebarsContext.Handlebars.Compile(original.BodyData.BodyAsFile); - string transformedBodyAsFilename = templateBodyAsFile(template); - - if (!useTransformerForBodyAsFile) - { - responseMessage.BodyData = new BodyData - { - DetectedBodyType = original.BodyData.DetectedBodyType, - DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, - BodyAsFile = transformedBodyAsFilename - }; - } - else - { - string text = handlebarsContext.FileSystemHandler.ReadResponseBodyAsString(transformedBodyAsFilename); - var templateBodyAsString = handlebarsContext.Handlebars.Compile(text); - - responseMessage.BodyData = new BodyData - { - DetectedBodyType = BodyType.String, - DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, - BodyAsString = templateBodyAsString(template), - BodyAsFile = transformedBodyAsFilename - }; - } - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using WireMock.Types; +using WireMock.Util; +using WireMock.Validation; + +namespace WireMock.Transformers.Handlebars +{ + internal class Transformer : ITransformer + { + private readonly ITransformerContextFactory _factory; + + public Transformer([NotNull] ITransformerContextFactory factory) + { + Check.NotNull(factory, nameof(factory)); + + _factory = factory; + } + + public ResponseMessage Transform(RequestMessage requestMessage, ResponseMessage original, bool useTransformerForBodyAsFile) + { + var handlebarsContext = _factory.Create(); + + var responseMessage = new ResponseMessage(); + + var model = new { request = requestMessage }; + + switch (original.BodyData?.DetectedBodyType) + { + case BodyType.Json: + TransformBodyAsJson(handlebarsContext, model, original, responseMessage); + break; + + case BodyType.File: + TransformBodyAsFile(handlebarsContext, model, original, responseMessage, useTransformerForBodyAsFile); + break; + + case BodyType.String: + responseMessage.BodyOriginal = original.BodyData.BodyAsString; + TransformBodyAsString(handlebarsContext, model, original, responseMessage); + break; + } + + responseMessage.FaultType = original.FaultType; + responseMessage.FaultPercentage = original.FaultPercentage; + + // Headers + var newHeaders = new Dictionary>(); + foreach (var header in original.Headers) + { + var headerKey = handlebarsContext.ParseAndRender(header.Key, model); + var templateHeaderValues = header.Value + .Select(text => handlebarsContext.ParseAndRender(text, model)) + .ToArray(); + + newHeaders.Add(headerKey, new WireMockList(templateHeaderValues)); + } + + responseMessage.Headers = newHeaders; + + switch (original.StatusCode) + { + case int statusCodeAsInteger: + responseMessage.StatusCode = statusCodeAsInteger; + break; + + case string statusCodeAsString: + responseMessage.StatusCode = handlebarsContext.ParseAndRender(statusCodeAsString, model); + break; + } + + return responseMessage; + } + + private static void TransformBodyAsJson(ITransformerContext handlebarsContext, object model, ResponseMessage original, ResponseMessage responseMessage) + { + JToken jToken; + switch (original.BodyData.BodyAsJson) + { + case JObject bodyAsJObject: + jToken = bodyAsJObject.DeepClone(); + WalkNode(handlebarsContext, jToken, model); + break; + + case Array bodyAsArray: + jToken = JArray.FromObject(bodyAsArray); + WalkNode(handlebarsContext, jToken, model); + break; + + case string bodyAsString: + jToken = ReplaceSingleNode(handlebarsContext, bodyAsString, model); + break; + + default: + jToken = JObject.FromObject(original.BodyData.BodyAsJson); + WalkNode(handlebarsContext, jToken, model); + break; + } + + responseMessage.BodyData = new BodyData + { + Encoding = original.BodyData.Encoding, + DetectedBodyType = original.BodyData.DetectedBodyType, + DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, + BodyAsJson = jToken + }; + } + + private static JToken ReplaceSingleNode(ITransformerContext handlebarsContext, string stringValue, object model) + { + string transformedString = handlebarsContext.ParseAndRender(stringValue, model); + + if (!string.Equals(stringValue, transformedString)) + { + const string property = "_"; + JObject dummy = JObject.Parse($"{{ \"{property}\": null }}"); + JToken node = dummy[property]; + + ReplaceNodeValue(node, transformedString); + + return dummy[property]; + } + + return stringValue; + } + + private static void WalkNode(ITransformerContext handlebarsContext, JToken node, object model) + { + if (node.Type == JTokenType.Object) + { + // In case of Object, loop all children. Do a ToArray() to avoid `Collection was modified` exceptions. + foreach (JProperty child in node.Children().ToArray()) + { + WalkNode(handlebarsContext, child.Value, model); + } + } + else if (node.Type == JTokenType.Array) + { + // In case of Array, loop all items. Do a ToArray() to avoid `Collection was modified` exceptions. + foreach (JToken child in node.Children().ToArray()) + { + WalkNode(handlebarsContext, child, model); + } + } + else if (node.Type == JTokenType.String) + { + // In case of string, try to transform the value. + string stringValue = node.Value(); + if (string.IsNullOrEmpty(stringValue)) + { + return; + } + + string transformedString = handlebarsContext.ParseAndRender(stringValue, model); + if (!string.Equals(stringValue, transformedString)) + { + ReplaceNodeValue(node, transformedString); + } + } + } + + private static void ReplaceNodeValue(JToken node, string stringValue) + { + if (bool.TryParse(stringValue, out bool valueAsBoolean)) + { + node.Replace(valueAsBoolean); + return; + } + + JToken value; + try + { + // Try to convert this string into a JsonObject + value = JToken.Parse(stringValue); + } + catch (JsonException) + { + // Ignore JsonException and just keep string value and convert to JToken + value = stringValue; + } + + node.Replace(value); + } + + private static void TransformBodyAsString(ITransformerContext handlebarsContext, object model, ResponseMessage original, ResponseMessage responseMessage) + { + responseMessage.BodyData = new BodyData + { + Encoding = original.BodyData.Encoding, + DetectedBodyType = original.BodyData.DetectedBodyType, + DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, + BodyAsString = handlebarsContext.ParseAndRender(original.BodyData.BodyAsString, model) + }; + } + + private void TransformBodyAsFile(ITransformerContext handlebarsContext, object model, ResponseMessage original, ResponseMessage responseMessage, bool useTransformerForBodyAsFile) + { + string transformedBodyAsFilename = handlebarsContext.ParseAndRender(original.BodyData.BodyAsFile, model); + + if (!useTransformerForBodyAsFile) + { + responseMessage.BodyData = new BodyData + { + DetectedBodyType = original.BodyData.DetectedBodyType, + DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, + BodyAsFile = transformedBodyAsFilename + }; + } + else + { + string text = handlebarsContext.FileSystemHandler.ReadResponseBodyAsString(transformedBodyAsFilename); + + responseMessage.BodyData = new BodyData + { + DetectedBodyType = BodyType.String, + DetectedBodyTypeFromContentType = original.BodyData.DetectedBodyTypeFromContentType, + BodyAsString = handlebarsContext.ParseAndRender(text, model), + BodyAsFile = transformedBodyAsFilename + }; + } + } + } } \ No newline at end of file diff --git a/src/WireMock.Net/WireMock.Net.csproj b/src/WireMock.Net/WireMock.Net.csproj index 98d03397..8f11d8e6 100644 --- a/src/WireMock.Net/WireMock.Net.csproj +++ b/src/WireMock.Net/WireMock.Net.csproj @@ -50,6 +50,12 @@ USE_ASPNETCORE;NET46 + + + + + + @@ -59,6 +65,7 @@ + @@ -78,6 +85,7 @@ + @@ -87,9 +95,11 @@ + + @@ -102,9 +112,11 @@ + + @@ -113,6 +125,7 @@ + diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyTests.cs index 2295453d..38791364 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyTests.cs @@ -1,8 +1,10 @@ using System; using System.Text; using System.Threading.Tasks; +using Moq; using Newtonsoft.Json.Linq; using NFluent; +using WireMock.Handlers; using WireMock.Models; using WireMock.ResponseBuilders; using WireMock.Settings; @@ -14,9 +16,19 @@ namespace WireMock.Net.Tests.ResponseBuilders { public class ResponseWithBodyTests { - private readonly WireMockServerSettings _settings = new WireMockServerSettings(); private const string ClientIp = "::1"; + private readonly Mock _filesystemHandlerMock; + private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + + public ResponseWithBodyTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + [Fact] public async Task Response_ProvideResponse_WithBody_Bytes_Encoding_Destination_String() { diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithCallbackTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithCallbackTests.cs index 31d67621..4af2e0b2 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithCallbackTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithCallbackTests.cs @@ -1,5 +1,7 @@ using System.Threading.Tasks; using FluentAssertions; +using Moq; +using WireMock.Handlers; using WireMock.Models; using WireMock.ResponseBuilders; using WireMock.Settings; @@ -11,8 +13,19 @@ namespace WireMock.Net.Tests.ResponseBuilders { public class ResponseWithCallbackTests { + private const string ClientIp = "::1"; + + private readonly Mock _filesystemHandlerMock; private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + public ResponseWithCallbackTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + [Fact] public async Task Response_WithCallbackAsync() { diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsHelpersTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsHelpersTests.cs index 963a95d6..6b8d08fc 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsHelpersTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsHelpersTests.cs @@ -1,5 +1,7 @@ using System.Threading.Tasks; +using Moq; using NFluent; +using WireMock.Handlers; using WireMock.Models; using WireMock.ResponseBuilders; using WireMock.Settings; @@ -11,9 +13,19 @@ namespace WireMock.Net.Tests.ResponseBuilders { public class ResponseWithHandlebarsHelpersTests { - private readonly WireMockServerSettings _settings = new WireMockServerSettings(); private const string ClientIp = "::1"; + private readonly Mock _filesystemHandlerMock; + private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + + public ResponseWithHandlebarsHelpersTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + [Fact] public async Task Response_ProvideResponseAsync_HandlebarsHelpers_String_Uppercase() { diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsJsonPathTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsJsonPathTests.cs index 1b7eedc9..6091d155 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsJsonPathTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsJsonPathTests.cs @@ -1,7 +1,11 @@ using System; +using System.Text; using System.Threading.Tasks; +using Moq; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NFluent; +using WireMock.Handlers; using WireMock.Models; using WireMock.ResponseBuilders; using WireMock.Settings; @@ -13,9 +17,19 @@ namespace WireMock.Net.Tests.ResponseBuilders { public class ResponseWithHandlebarsJsonPathTests { - private readonly WireMockServerSettings _settings = new WireMockServerSettings(); private const string ClientIp = "::1"; + private readonly Mock _filesystemHandlerMock; + private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + + public ResponseWithHandlebarsJsonPathTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + [Fact] public async Task Response_ProvideResponse_Handlebars_JsonPath_SelectToken_Object_ResponseBodyAsJson() { @@ -333,5 +347,32 @@ namespace WireMock.Net.Tests.ResponseBuilders // Act Check.ThatAsyncCode(() => response.ProvideResponseAsync(request, _settings)).Throws(); } + + [Fact] + public async Task Response_ProvideResponse_Transformer_WithBodyAsFile_JsonPath() + { + // Assign + string jsonString = "{ \"MyUniqueNumber\": \"1\" }"; + var bodyData = new BodyData + { + BodyAsString = jsonString, + BodyAsJson = JsonConvert.DeserializeObject(jsonString), + DetectedBodyType = BodyType.Json, + DetectedBodyTypeFromContentType = BodyType.Json, + Encoding = Encoding.UTF8 + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, bodyData); + + string jsonPath = "\"$.MyUniqueNumber\""; + var response = Response.Create() + .WithTransformer() + .WithBodyFromFile(@"c:\\{{JsonPath.SelectToken request.body " + jsonPath + "}}\\test.json"); // why use a \\ here ? + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.json"); + } } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsLinqTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsLinqTests.cs index 72dc99fb..6b5d3370 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsLinqTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsLinqTests.cs @@ -1,7 +1,9 @@ using System; using System.Threading.Tasks; +using Moq; using Newtonsoft.Json.Linq; using NFluent; +using WireMock.Handlers; using WireMock.Models; using WireMock.ResponseBuilders; using WireMock.Settings; @@ -13,8 +15,17 @@ namespace WireMock.Net.Tests.ResponseBuilders { public class ResponseWithHandlebarsLinqTests { + private readonly Mock _filesystemHandlerMock; private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + public ResponseWithHandlebarsLinqTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + [Fact] public async Task Response_ProvideResponse_Handlebars_Linq1_String0() { diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRandomTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRandomTests.cs index 08837988..75d2d5f6 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRandomTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRandomTests.cs @@ -1,7 +1,9 @@ using System.Linq; using System.Threading.Tasks; +using Moq; using Newtonsoft.Json.Linq; using NFluent; +using WireMock.Handlers; using WireMock.Models; using WireMock.ResponseBuilders; using WireMock.Settings; @@ -11,9 +13,19 @@ namespace WireMock.Net.Tests.ResponseBuilders { public class ResponseWithHandlebarsRandomTests { - private readonly WireMockServerSettings _settings = new WireMockServerSettings(); private const string ClientIp = "::1"; + private readonly Mock _filesystemHandlerMock; + private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + + public ResponseWithHandlebarsRandomTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + [Fact] public async Task Response_ProvideResponseAsync_Handlebars_Random1() { diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRegexTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRegexTests.cs index c719e438..b58cce81 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRegexTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRegexTests.cs @@ -1,6 +1,8 @@ using System; using System.Threading.Tasks; +using Moq; using NFluent; +using WireMock.Handlers; using WireMock.Models; using WireMock.ResponseBuilders; using WireMock.Settings; @@ -12,9 +14,19 @@ namespace WireMock.Net.Tests.ResponseBuilders { public class ResponseWithHandlebarsRegexTests { - private readonly WireMockServerSettings _settings = new WireMockServerSettings(); private const string ClientIp = "::1"; + private readonly Mock _filesystemHandlerMock; + private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + + public ResponseWithHandlebarsRegexTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + [Fact] public async Task Response_ProvideResponseAsync_Handlebars_RegexMatch() { diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsXPathTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsXPathTests.cs index df9e96d2..48baf5f9 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsXPathTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsXPathTests.cs @@ -7,6 +7,8 @@ using WireMock.Settings; using WireMock.Types; using WireMock.Util; using Xunit; +using Moq; +using WireMock.Handlers; #if !NETSTANDARD1_3 using Wmhelp.XPath2; #endif @@ -15,9 +17,19 @@ namespace WireMock.Net.Tests.ResponseBuilders { public class ResponseWithHandlebarsXPathTests { - private readonly WireMockServerSettings _settings = new WireMockServerSettings(); private const string ClientIp = "::1"; + private readonly Mock _filesystemHandlerMock; + private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + + public ResponseWithHandlebarsXPathTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + [Fact] public async Task Response_ProvideResponse_Handlebars_XPath_SelectSingleNode_Request_BodyAsString() { diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsXegerTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsXegerTests.cs index e5f19b92..1c53c46b 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsXegerTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsXegerTests.cs @@ -2,6 +2,7 @@ using Newtonsoft.Json.Linq; using NFluent; using System.Threading.Tasks; +using WireMock.Handlers; using WireMock.Models; using WireMock.ResponseBuilders; using WireMock.Settings; @@ -11,9 +12,19 @@ namespace WireMock.Net.Tests.ResponseBuilders { public class ResponseWithHandlebarsXegerTests { - private readonly WireMockServerSettings _settings = new WireMockServerSettings(); private const string ClientIp = "::1"; + private readonly Mock _filesystemHandlerMock; + private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + + public ResponseWithHandlebarsXegerTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + [Fact] public async Task Response_ProvideResponseAsync_Handlebars_Xeger1() { diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithScribanTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithScribanTests.cs new file mode 100644 index 00000000..e0e8f680 --- /dev/null +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithScribanTests.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading.Tasks; +using FluentAssertions; +using NFluent; +using WireMock.Models; +using WireMock.ResponseBuilders; +using WireMock.Settings; +using WireMock.Types; +using WireMock.Util; +using Xunit; +using WireMock.Handlers; +using Moq; +#if NET452 +using Microsoft.Owin; +#else +using Microsoft.AspNetCore.Http; +#endif + +namespace WireMock.Net.Tests.ResponseBuilders +{ + public class ResponseWithScribanTests + { + private const string ClientIp = "::1"; + + private readonly Mock _filesystemHandlerMock; + private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + + public ResponseWithScribanTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + + [Fact] + public async Task Response_ProvideResponse_DotLiquid_WithNullBody_ShouldNotThrowException() + { + // Assign + var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock")); + var request = new RequestMessage(urlDetails, "GET", ClientIp); + + var response = Response.Create().WithTransformer(TransformerType.ScribanDotLiquid); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + responseMessage.BodyData.Should().BeNull(); + } + + [Fact] + public async Task Response_ProvideResponse_DotLiquid_UrlPathVerb() + { + // Assign + var body = new BodyData + { + BodyAsString = "whatever", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POSt", ClientIp, body); + + var response = Response.Create() + .WithBody("test {{request.Url}} {{request.Path}} {{request.Method}}") + .WithTransformer(TransformerType.Scriban); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test http://localhost/foo /foo POSt"); + } + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithTransformerTests.cs similarity index 57% rename from test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs rename to test/WireMock.Net.Tests/ResponseBuilders/ResponseWithTransformerTests.cs index db1eaf88..d4685e3e 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithTransformerTests.cs @@ -1,432 +1,585 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using FluentAssertions; -using Moq; -using Newtonsoft.Json; -using NFluent; -using WireMock.Handlers; -using WireMock.Models; -using WireMock.ResponseBuilders; -using WireMock.Settings; -using WireMock.Types; -using WireMock.Util; -using Xunit; -#if NET452 -using Microsoft.Owin; -#else -using Microsoft.AspNetCore.Http; -#endif - -namespace WireMock.Net.Tests.ResponseBuilders -{ - public class ResponseWithHandlebarsTests - { - private readonly WireMockServerSettings _settings = new WireMockServerSettings(); - private const string ClientIp = "::1"; - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithNullBody_ShouldNotThrowException() - { - // Assign - var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock")); - var request = new RequestMessage(urlDetails, "GET", ClientIp); - - var response = Response.Create() - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - responseMessage.BodyData.Should().BeNull(); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_UrlPathVerb() - { - // Assign - var body = new BodyData - { - BodyAsString = "whatever", - DetectedBodyType = BodyType.String - }; - var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POSt", ClientIp, body); - - var response = Response.Create() - .WithBody("test {{request.url}} {{request.path}} {{request.method}}") - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsString).Equals("test http://localhost/foo /foo POSt"); - } - - [Theory] - [InlineData("Get")] - [InlineData("Post")] - public async Task Response_ProvideResponse_Handlebars_UrlPath(string httpMethod) - { - // Assign - var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock")); - var request = new RequestMessage(urlDetails, httpMethod, ClientIp); - - var response = Response.Create() - .WithBody("{{request.url}} {{request.absoluteurl}} {{request.path}} {{request.absolutepath}}") - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsString).Equals("http://localhost/a/b http://localhost/wiremock/a/b /a/b /wiremock/a/b"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_PathSegments() - { - // Assign - var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock")); - var request = new RequestMessage(urlDetails, "POST", ClientIp); - - var response = Response.Create() - .WithBody("{{request.pathsegments.[0]}} {{request.absolutepathsegments.[0]}}") - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsString).Equals("a wiremock"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_Query() - { - // Assign - var body = new BodyData - { - BodyAsString = "abc", - DetectedBodyType = BodyType.String - }; - var request = new RequestMessage(new UrlDetails("http://localhost/foo?a=1&a=2&b=5"), "POST", ClientIp, body); - - var response = Response.Create() - .WithBody("test keya={{request.query.a}} idx={{request.query.a.[0]}} idx={{request.query.a.[1]}} keyb={{request.query.b}}") - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsString).Equals("test keya=1 idx=1 idx=2 keyb=5"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_StatusCode() - { - // Assign - var body = new BodyData - { - BodyAsString = "abc", - DetectedBodyType = BodyType.String - }; - var request = new RequestMessage(new UrlDetails("http://localhost/foo?a=400"), "POST", ClientIp, body); - - var response = Response.Create() - .WithStatusCode("{{request.query.a}}") - .WithBody("test") - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); - Check.That(responseMessage.StatusCode).Equals("400"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_StatusCodeIsNull() - { - // Assign - var body = new BodyData - { - BodyAsString = "abc", - DetectedBodyType = BodyType.String - }; - var request = new RequestMessage(new UrlDetails("http://localhost/foo?a=400"), "POST", ClientIp, body); - - var response = Response.Create() - .WithBody("test") - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); - Check.That(responseMessage.StatusCode).Equals(null); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_Header() - { - // Assign - var body = new BodyData - { - BodyAsString = "abc", - DetectedBodyType = BodyType.String - }; - var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body, new Dictionary { { "Content-Type", new[] { "text/plain" } } }); - - var response = Response.Create().WithHeader("x", "{{request.headers.Content-Type}}").WithBody("test").WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); - Check.That(responseMessage.Headers).ContainsKey("x"); - Check.That(responseMessage.Headers["x"]).ContainsExactly("text/plain"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_Headers() - { - // Assign - var body = new BodyData - { - BodyAsString = "abc", - DetectedBodyType = BodyType.String - }; - var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body, new Dictionary { { "Content-Type", new[] { "text/plain" } } }); - - var response = Response.Create().WithHeader("x", "{{request.headers.Content-Type}}", "{{request.url}}").WithBody("test").WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); - Check.That(responseMessage.Headers).ContainsKey("x"); - Check.That(responseMessage.Headers["x"]).Contains("text/plain"); - Check.That(responseMessage.Headers["x"]).Contains("http://localhost/foo"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_Origin_Port_Protocol_Host() - { - // Assign - var body = new BodyData - { - BodyAsString = "abc", - DetectedBodyType = BodyType.String - }; - var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", ClientIp, body); - - var response = Response.Create() - .WithBody("test {{request.origin}} {{request.port}} {{request.protocol}} {{request.host}}") - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsString).Equals("test http://localhost:1234 1234 http localhost"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithBodyAsJson_ResultAsObject() - { - // Assign - string jsonString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }"; - 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 response = Response.Create() - .WithBodyAsJson(new { x = "test {{request.path}}" }) - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("{\"x\":\"test /foo_object\"}"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithBodyAsJson_ResultAsArray() - { - // Assign - string jsonString = "{ \"a\": \"test 1\", \"b\": \"test 2\" }"; - var bodyData = new BodyData - { - BodyAsJson = JsonConvert.DeserializeObject(jsonString), - DetectedBodyType = BodyType.Json, - Encoding = Encoding.UTF8 - }; - var request = new RequestMessage(new UrlDetails("http://localhost/foo_array"), "POST", ClientIp, bodyData); - - var response = Response.Create() - .WithBodyAsJson(new[] { "first", "{{request.path}}", "{{request.bodyAsJson.a}}", "{{request.bodyAsJson.b}}", "last" }) - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("[\"first\",\"/foo_array\",\"test 1\",\"test 2\",\"last\"]"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithBodyAsFile() - { - // Assign - var request = new RequestMessage(new UrlDetails("http://localhost/foo?MyUniqueNumber=1"), "GET", ClientIp); - - var response = Response.Create() - .WithTransformer() - .WithBodyFromFile(@"c:\\{{request.query.MyUniqueNumber}}\\test.xml"); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.xml"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithBodyAsFile_And_TransformContentFromBodyAsFile() - { - // Assign - var filesystemHandlerMock = new Mock(MockBehavior.Strict); - filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns(""); - - _settings.FileSystemHandler = filesystemHandlerMock.Object; - - var request = new RequestMessage(new UrlDetails("http://localhost/foo?MyUniqueNumber=1"), "GET", ClientIp); - - var response = Response.Create() - .WithTransformer(true) - .WithBodyFromFile(@"c:\\{{request.query.MyUniqueNumber}}\\test.xml"); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.xml"); - Check.That(responseMessage.BodyData.DetectedBodyType).Equals(BodyType.String); - Check.That(responseMessage.BodyData.BodyAsString).Equals(""); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithBodyAsFile_JsonPath() - { - // Assign - string jsonString = "{ \"MyUniqueNumber\": \"1\" }"; - var bodyData = new BodyData - { - BodyAsString = jsonString, - BodyAsJson = JsonConvert.DeserializeObject(jsonString), - DetectedBodyType = BodyType.Json, - DetectedBodyTypeFromContentType = BodyType.Json, - Encoding = Encoding.UTF8 - }; - var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, bodyData); - - string jsonPath = "\"$.MyUniqueNumber\""; - var response = Response.Create() - .WithTransformer() - .WithBodyFromFile(@"c:\\{{JsonPath.SelectToken request.body " + jsonPath + "}}\\test.json"); // why use a \\ here ? - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.json"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithBodyAsJson_ResultAsNormalString() - { - // Assign - string jsonString = "{ \"name\": \"WireMock\" }"; - 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 response = Response.Create() - .WithBodyAsJson("test") - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("\"test\""); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithBodyAsJson_ResultAsHandlebarsString() - { - // Assign - string jsonString = "{ \"name\": \"WireMock\" }"; - 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 response = Response.Create() - .WithBodyAsJson("{{{request.bodyAsJson}}}") - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("{\"name\":\"WireMock\"}"); - } - - [Fact] - public async Task Response_ProvideResponse_Handlebars_WithBodyAsString_KeepsEncoding() - { - // Assign - const string text = "my-text"; - Encoding enc = Encoding.Unicode; - var bodyData = new BodyData - { - BodyAsString = text, - DetectedBodyType = BodyType.String, - Encoding = enc - }; - var request = new RequestMessage(new UrlDetails("http://localhost/foo_object"), "POST", ClientIp, bodyData); - - var response = Response.Create() - .WithBody("{{request.body}}", BodyDestinationFormat.SameAsSource, enc) - .WithTransformer(); - - // Act - var responseMessage = await response.ProvideResponseAsync(request, _settings); - - // Assert - responseMessage.BodyData.BodyAsString.Should().Be(text); - responseMessage.BodyData.Encoding.Should().Be(enc); - } - } +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using FluentAssertions; +using Moq; +using Newtonsoft.Json; +using NFluent; +using WireMock.Handlers; +using WireMock.Models; +using WireMock.ResponseBuilders; +using WireMock.Settings; +using WireMock.Types; +using WireMock.Util; +using Xunit; +#if NET452 +using Microsoft.Owin; +#else +using Microsoft.AspNetCore.Http; +#endif + +namespace WireMock.Net.Tests.ResponseBuilders +{ + public class ResponseWithTransformerTests + { + private readonly Mock _filesystemHandlerMock; + private readonly WireMockServerSettings _settings = new WireMockServerSettings(); + + private const string ClientIp = "::1"; + + public ResponseWithTransformerTests() + { + _filesystemHandlerMock = new Mock(MockBehavior.Strict); + _filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); + + _settings.FileSystemHandler = _filesystemHandlerMock.Object; + } + + [Theory] + [InlineData(TransformerType.Handlebars)] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Transformer_WithNullBody_ShouldNotThrowException(TransformerType transformerType) + { + // Assign + var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock")); + var request = new RequestMessage(urlDetails, "GET", ClientIp); + + var response = Response.Create().WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + responseMessage.BodyData.Should().BeNull(); + } + + [Theory] + [InlineData(TransformerType.Handlebars)] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Transformer_UrlPathVerb(TransformerType transformerType) + { + // Assign + var body = new BodyData + { + BodyAsString = "whatever", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POSt", ClientIp, body); + + var response = Response.Create() + .WithBody("test {{request.Url}} {{request.Path}} {{request.Method}}") + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test http://localhost/foo /foo POSt"); + } + + [Theory] + [InlineData(TransformerType.Handlebars, "Get")] + [InlineData(TransformerType.Handlebars, "Post")] + [InlineData(TransformerType.Scriban, "Get")] + [InlineData(TransformerType.Scriban, "Post")] + [InlineData(TransformerType.ScribanDotLiquid, "Get")] + [InlineData(TransformerType.ScribanDotLiquid, "Post")] + public async Task Response_ProvideResponse_Transformer_UrlPath(TransformerType transformerType, string httpMethod) + { + // Assign + var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock")); + var request = new RequestMessage(urlDetails, httpMethod, ClientIp); + + var response = Response.Create() + .WithBody("url={{request.Url}} absoluteurl={{request.AbsoluteUrl}} path={{request.Path}} absolutepath={{request.AbsolutePath}}") + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("url=http://localhost/a/b absoluteurl=http://localhost/wiremock/a/b path=/a/b absolutepath=/wiremock/a/b"); + } + + [Fact] + public async Task Response_ProvideResponse_Handlebars_PathSegments() + { + // Assign + var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock")); + var request = new RequestMessage(urlDetails, "POST", ClientIp); + + var response = Response.Create() + .WithBody("{{request.PathSegments.[0]}} {{request.AbsolutePathSegments.[0]}}") + .WithTransformer(); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("a wiremock"); + } + + [Theory(Skip = "Invalid token `OpenBracket`")] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Scriban_PathSegments(TransformerType transformerType) + { + // Assign + var urlDetails = UrlUtils.Parse(new Uri("http://localhost/wiremock/a/b"), new PathString("/wiremock")); + var request = new RequestMessage(urlDetails, "POST", ClientIp); + + var response = Response.Create() + .WithBody("{{request.PathSegments.[0]}} {{request.AbsolutePathSegments.[0]}}") + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("a wiremock"); + } + + [Fact] + public async Task Response_ProvideResponse_Handlebars_Query() + { + // Assign + var body = new BodyData + { + BodyAsString = "abc", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo?a=1&a=2&b=5"), "POST", ClientIp, body); + + var response = Response.Create() + .WithBody("test keya={{request.query.a}} idx={{request.query.a.[0]}} idx={{request.query.a.[1]}} keyb={{request.query.b}}") + .WithTransformer(); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test keya=1 idx=1 idx=2 keyb=5"); + } + + [Theory(Skip = "Invalid token `OpenBracket`")] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Scriban_Query(TransformerType transformerType) + { + // Assign + var body = new BodyData + { + BodyAsString = "abc", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo?a=1&a=2&b=5"), "POST", ClientIp, body); + + var response = Response.Create() + .WithBody("test keya={{request.query.a}} idx={{request.query.a.[0]}} idx={{request.query.a.[1]}} keyb={{request.query.b}}") + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test keya=1 idx=1 idx=2 keyb=5"); + } + + [Fact] + public async Task Response_ProvideResponse_Handlebars_StatusCode() + { + // Assign + var body = new BodyData + { + BodyAsString = "abc", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo?a=400"), "POST", ClientIp, body); + + var response = Response.Create() + .WithStatusCode("{{request.query.a}}") + .WithBody("test") + .WithTransformer(); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); + Check.That(responseMessage.StatusCode).Equals("400"); + } + + [Theory(Skip = "WireMockList is not supported by Scriban")] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Scriban_StatusCode(TransformerType transformerType) + { + // Assign + var body = new BodyData + { + BodyAsString = "abc", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo?a=400"), "POST", ClientIp, body); + + var response = Response.Create() + .WithStatusCode("{{request.Query.a}}") + .WithBody("test") + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); + Check.That(responseMessage.StatusCode).Equals("400"); + } + + [Theory] + [InlineData(TransformerType.Handlebars)] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Transformer_StatusCodeIsNull(TransformerType transformerType) + { + // Assign + var body = new BodyData + { + BodyAsString = "abc", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo?a=400"), "POST", ClientIp, body); + + var response = Response.Create() + .WithBody("test") + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); + Check.That(responseMessage.StatusCode).Equals(null); + } + + [Fact] + public async Task Response_ProvideResponse_Handlebars_Header() + { + // Assign + var body = new BodyData + { + BodyAsString = "abc", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body, new Dictionary { { "Content-Type", new[] { "text/plain" } } }); + + var response = Response.Create().WithHeader("x", "{{request.headers.Content-Type}}").WithBody("test").WithTransformer(); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); + Check.That(responseMessage.Headers).ContainsKey("x"); + Check.That(responseMessage.Headers["x"]).ContainsExactly("text/plain"); + } + + [Fact] + public async Task Response_ProvideResponse_Handlebars_Headers() + { + // Assign + var body = new BodyData + { + BodyAsString = "abc", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body, new Dictionary { { "Content-Type", new[] { "text/plain" } } }); + + var response = Response.Create().WithHeader("x", "{{request.headers.Content-Type}}", "{{request.url}}").WithBody("test").WithTransformer(); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); + Check.That(responseMessage.Headers).ContainsKey("x"); + Check.That(responseMessage.Headers["x"]).Contains("text/plain"); + Check.That(responseMessage.Headers["x"]).Contains("http://localhost/foo"); + } + + [Theory(Skip = "WireMockList is not supported by Scriban")] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Scriban_Headers(TransformerType transformerType) + { + // Assign + var body = new BodyData + { + BodyAsString = "abc", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body, new Dictionary { { "Content-Type", new[] { "text/plain" } } }); + + var response = Response.Create().WithHeader("x", "{{request.Headers[\"Content-Type\"]}}", "{{request.Url}}").WithBody("test").WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test"); + Check.That(responseMessage.Headers).ContainsKey("x"); + Check.That(responseMessage.Headers["x"]).Contains("text/plain"); + Check.That(responseMessage.Headers["x"]).Contains("http://localhost/foo"); + } + + [Theory] + [InlineData(TransformerType.Handlebars)] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Transformer_Origin_Port_Protocol_Host(TransformerType transformerType) + { + // Assign + var body = new BodyData + { + BodyAsString = "abc", + DetectedBodyType = BodyType.String + }; + var request = new RequestMessage(new UrlDetails("http://localhost:1234"), "POST", ClientIp, body); + + var response = Response.Create() + .WithBody("test {{request.Origin}} {{request.Port}} {{request.Protocol}} {{request.Host}}") + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsString).Equals("test http://localhost:1234 1234 http localhost"); + } + + [Theory] + [InlineData(TransformerType.Handlebars)] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Transformer_WithBodyAsJson_ResultAsObject(TransformerType transformerType) + { + // Assign + string jsonString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }"; + 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 response = Response.Create() + .WithBodyAsJson(new { x = "test {{request.Path}}" }) + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("{\"x\":\"test /foo_object\"}"); + } + + [Theory] + [InlineData(TransformerType.Handlebars)] + //[InlineData(TransformerType.Scriban)] Scriban cannot access dynamic Json Objects + //[InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Transformer_WithBodyAsJson_ResultAsArray(TransformerType transformerType) + { + // Assign + string jsonString = "{ \"a\": \"test 1\", \"b\": \"test 2\" }"; + var bodyData = new BodyData + { + BodyAsJson = JsonConvert.DeserializeObject(jsonString), + DetectedBodyType = BodyType.Json, + Encoding = Encoding.UTF8 + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo_array"), "POST", ClientIp, bodyData); + + var response = Response.Create() + .WithBodyAsJson(new[] { "first", "{{request.path}}", "{{request.bodyAsJson.a}}", "{{request.bodyAsJson.b}}", "last" }) + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("[\"first\",\"/foo_array\",\"test 1\",\"test 2\",\"last\"]"); + } + + [Fact] + public async Task Response_ProvideResponse_Handlebars_WithBodyAsFile() + { + // Assign + var request = new RequestMessage(new UrlDetails("http://localhost/foo?MyUniqueNumber=1"), "GET", ClientIp); + + var response = Response.Create() + .WithTransformer() + .WithBodyFromFile(@"c:\\{{request.query.MyUniqueNumber}}\\test.xml"); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.xml"); + } + + [Theory(Skip = @"Does not work in Scriban --> c:\\[""1""]\\test.xml")] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Scriban_WithBodyAsFile(TransformerType transformerType) + { + // Assign + var request = new RequestMessage(new UrlDetails("http://localhost/foo?MyUniqueNumber=1"), "GET", ClientIp); + + var response = Response.Create() + .WithTransformer(transformerType) + .WithBodyFromFile(@"c:\\{{request.query.MyUniqueNumber}}\\test.xml"); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.xml"); + } + + [Theory] + [InlineData(TransformerType.Handlebars)] + //[InlineData(TransformerType.Scriban)] ["c:\\["1"]\\test.xml"] + //[InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Transformer_WithBodyAsFile_And_TransformContentFromBodyAsFile(TransformerType transformerType) + { + // Assign + var filesystemHandlerMock = new Mock(MockBehavior.Strict); + filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns(""); + + _settings.FileSystemHandler = filesystemHandlerMock.Object; + + var request = new RequestMessage(new UrlDetails("http://localhost/foo?MyUniqueNumber=1"), "GET", ClientIp); + + var response = Response.Create() + .WithTransformer(transformerType, true) + .WithBodyFromFile(@"c:\\{{request.query.MyUniqueNumber}}\\test.xml"); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(responseMessage.BodyData.BodyAsFile).Equals(@"c:\1\test.xml"); + Check.That(responseMessage.BodyData.DetectedBodyType).Equals(BodyType.String); + Check.That(responseMessage.BodyData.BodyAsString).Equals(""); + } + + [Theory] + [InlineData(TransformerType.Handlebars)] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Transformer_WithBodyAsJson_ResultAsNormalString(TransformerType transformerType) + { + // Assign + string jsonString = "{ \"name\": \"WireMock\" }"; + 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 response = Response.Create() + .WithBodyAsJson("test") + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("\"test\""); + } + + [Fact] + public async Task Response_ProvideResponse_Handlebars_WithBodyAsJson_ResultAsTemplatedString() + { + // Assign + string jsonString = "{ \"name\": \"WireMock\" }"; + 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 response = Response.Create() + .WithBodyAsJson("{{{request.BodyAsJson}}}") + .WithTransformer(); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("{\"name\":\"WireMock\"}"); + } + + [Theory(Skip = "{{{ }}} Does not work in Scriban")] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Scriban_WithBodyAsJson_ResultAsTemplatedString(TransformerType transformerType) + { + // Assign + string jsonString = "{ \"name\": \"WireMock\" }"; + 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 response = Response.Create() + .WithBodyAsJson("{{{request.BodyAsJson}}}") + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + Check.That(JsonConvert.SerializeObject(responseMessage.BodyData.BodyAsJson)).Equals("{\"name\":\"WireMock\"}"); + } + + [Theory] + [InlineData(TransformerType.Handlebars)] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public async Task Response_ProvideResponse_Transformer_WithBodyAsString_KeepsEncoding(TransformerType transformerType) + { + // Assign + const string text = "my-text"; + Encoding enc = Encoding.Unicode; + var bodyData = new BodyData + { + BodyAsString = text, + DetectedBodyType = BodyType.String, + Encoding = enc + }; + var request = new RequestMessage(new UrlDetails("http://localhost/foo_object"), "POST", ClientIp, bodyData); + + var response = Response.Create() + .WithBody("{{request.Body}}", BodyDestinationFormat.SameAsSource, enc) + .WithTransformer(transformerType); + + // Act + var responseMessage = await response.ProvideResponseAsync(request, _settings); + + // Assert + responseMessage.BodyData.BodyAsString.Should().Be(text); + responseMessage.BodyData.Encoding.Should().Be(enc); + } + } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Transformers/HandlebarsContextFactoryTests.cs b/test/WireMock.Net.Tests/Transformers/Handlebars/HandlebarsContextFactoryTests.cs similarity index 89% rename from test/WireMock.Net.Tests/Transformers/HandlebarsContextFactoryTests.cs rename to test/WireMock.Net.Tests/Transformers/Handlebars/HandlebarsContextFactoryTests.cs index 16fd3712..59bb036e 100644 --- a/test/WireMock.Net.Tests/Transformers/HandlebarsContextFactoryTests.cs +++ b/test/WireMock.Net.Tests/Transformers/Handlebars/HandlebarsContextFactoryTests.cs @@ -1,52 +1,52 @@ -using FluentAssertions; -using HandlebarsDotNet; -using Moq; -using System; -using WireMock.Handlers; -using WireMock.Transformers; -using Xunit; - -namespace WireMock.Net.Tests.Transformers -{ - public class HandlebarsContextFactoryTests - { - private readonly Mock _fileSystemHandlerMock = new Mock(); - - [Fact] - public void Create_WithNullAction_DoesNotInvokeAction() - { - // Arrange - var sut = new HandlebarsContextFactory(_fileSystemHandlerMock.Object, null); - - // Act - var result = sut.Create(); - - // Assert - result.Should().NotBeNull(); - } - - [Fact] - public void Create_WithAction_InvokesAction() - { - // Arrange - int num = 0; - Action action = (ctx, fs) => - { - ctx.Should().NotBeNull(); - fs.Should().NotBeNull(); - - num++; - }; - var sut = new HandlebarsContextFactory(_fileSystemHandlerMock.Object, action); - - // Act - var result = sut.Create(); - - // Assert - result.Should().NotBeNull(); - - // Verify - num.Should().Be(1); - } - } -} +using FluentAssertions; +using HandlebarsDotNet; +using Moq; +using System; +using WireMock.Handlers; +using WireMock.Transformers.Handlebars; +using Xunit; + +namespace WireMock.Net.Tests.Transformers.Handlebars +{ + public class HandlebarsContextFactoryTests + { + private readonly Mock _fileSystemHandlerMock = new Mock(); + + [Fact] + public void Create_WithNullAction_DoesNotInvokeAction() + { + // Arrange + var sut = new HandlebarsContextFactory(_fileSystemHandlerMock.Object, null); + + // Act + var result = sut.Create(); + + // Assert + result.Should().NotBeNull(); + } + + [Fact] + public void Create_WithAction_InvokesAction() + { + // Arrange + int num = 0; + Action action = (ctx, fs) => + { + ctx.Should().NotBeNull(); + fs.Should().NotBeNull(); + + num++; + }; + var sut = new HandlebarsContextFactory(_fileSystemHandlerMock.Object, action); + + // Act + var result = sut.Create(); + + // Assert + result.Should().NotBeNull(); + + // Verify + num.Should().Be(1); + } + } +} diff --git a/test/WireMock.Net.Tests/Transformers/Scriban/ScribanContextFactoryTests.cs b/test/WireMock.Net.Tests/Transformers/Scriban/ScribanContextFactoryTests.cs new file mode 100644 index 00000000..6217fbf8 --- /dev/null +++ b/test/WireMock.Net.Tests/Transformers/Scriban/ScribanContextFactoryTests.cs @@ -0,0 +1,40 @@ +using System; +using FluentAssertions; +using Moq; +using WireMock.Handlers; +using WireMock.Transformers.Scriban; +using WireMock.Types; +using Xunit; + +namespace WireMock.Net.Tests.Transformers.Scriban +{ + public class ScribanContextFactoryTests + { + private readonly Mock _fileSystemHandlerMock = new Mock(); + + [Theory] + [InlineData(TransformerType.Scriban)] + [InlineData(TransformerType.ScribanDotLiquid)] + public void Create_With_Scriban_TransformerType_Creates_ITransformerContext(TransformerType transformerType) + { + // Arrange + var sut = new ScribanContextFactory(_fileSystemHandlerMock.Object, transformerType); + + // Act + var result = sut.Create(); + + // Assert + result.Should().NotBeNull(); + } + + [Fact] + public void Create_With_Invalid_TransformerType_Throws_Exception() + { + // Act + Action action = () => new ScribanContextFactory(_fileSystemHandlerMock.Object, TransformerType.Handlebars); + + // Assert + action.Should().Throw(); + } + } +} \ No newline at end of file