Throw exception in case WithTransformer is used after WithBodyFromFile (#1185)

* Fix .WithBodyFromFile + .WithTransformer combination

* Ex
This commit is contained in:
Stef Heyenrath
2024-09-29 21:29:34 +02:00
committed by GitHub
parent edbc7aeb5c
commit 76ae1466cc
7 changed files with 151 additions and 33 deletions

View File

@@ -13,6 +13,8 @@ namespace WireMock.ResponseBuilders;
public partial class Response
{
private bool _bodyFromFileSet;
/// <inheritdoc />
public IResponseBuilder WithBody(Func<IRequestMessage, string> bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null)
{
@@ -78,6 +80,8 @@ public partial class Response
{
Guard.NotNull(filename);
_bodyFromFileSet = true;
ResponseMessage.BodyData = new BodyData
{
BodyAsFileIsCached = cache,

View File

@@ -0,0 +1,36 @@
// Copyright © WireMock.Net
using System;
using WireMock.Types;
namespace WireMock.ResponseBuilders;
public partial class Response
{
/// <inheritdoc cref="ITransformResponseBuilder.WithTransformer(bool)"/>
public IResponseBuilder WithTransformer(bool transformContentFromBodyAsFile)
{
return WithTransformer(TransformerType.Handlebars, transformContentFromBodyAsFile);
}
/// <inheritdoc cref="ITransformResponseBuilder.WithTransformer(ReplaceNodeOptions)"/>
public IResponseBuilder WithTransformer(ReplaceNodeOptions options)
{
return WithTransformer(TransformerType.Handlebars, false, options);
}
/// <inheritdoc />
public IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.EvaluateAndTryToConvert)
{
if (_bodyFromFileSet)
{
throw new InvalidOperationException("WithTransformer should be used before WithBodyFromFile.");
}
UseTransformer = true;
TransformerType = transformerType;
UseTransformerForBodyAsFile = transformContentFromBodyAsFile;
TransformerReplaceNodeOptions = options;
return this;
}
}

View File

@@ -164,28 +164,6 @@ public partial class Response : IResponseBuilder
return WithStatusCode((int)HttpStatusCode.NotFound);
}
/// <inheritdoc cref="ITransformResponseBuilder.WithTransformer(bool)"/>
public IResponseBuilder WithTransformer(bool transformContentFromBodyAsFile)
{
return WithTransformer(TransformerType.Handlebars, transformContentFromBodyAsFile);
}
/// <inheritdoc cref="ITransformResponseBuilder.WithTransformer(ReplaceNodeOptions)"/>
public IResponseBuilder WithTransformer(ReplaceNodeOptions options)
{
return WithTransformer(TransformerType.Handlebars, false, options);
}
/// <inheritdoc />
public IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.EvaluateAndTryToConvert)
{
UseTransformer = true;
TransformerType = transformerType;
UseTransformerForBodyAsFile = transformContentFromBodyAsFile;
TransformerReplaceNodeOptions = options;
return this;
}
/// <inheritdoc />
public IResponseBuilder WithDelay(TimeSpan delay)
{
@@ -286,7 +264,7 @@ public partial class Response : IResponseBuilder
if (UseTransformer)
{
// Check if the body matcher is a RequestMessageProtoBufMatcher and try to to decode the byte-array to a BodyAsJson.
// Check if the body matcher is a RequestMessageProtoBufMatcher and try to decode the byte-array to a BodyAsJson.
if (mapping.RequestMatcher is Request requestMatcher && requestMessage is RequestMessage request)
{
var protoBufMatcher = requestMatcher.GetRequestMessageMatcher<RequestMessageProtoBufMatcher>()?.Matcher;

View File

@@ -198,7 +198,7 @@ internal class Transformer : ITransformer
private JToken ReplaceSingleNode(ITransformerContext transformerContext, ReplaceNodeOptions options, string stringValue, object model)
{
string transformedString = transformerContext.ParseAndRender(stringValue, model);
var transformedString = transformerContext.ParseAndRender(stringValue, model);
if (!string.Equals(stringValue, transformedString))
{
@@ -346,7 +346,7 @@ internal class Transformer : ITransformer
private static IBodyData TransformBodyAsFile(ITransformerContext transformerContext, object model, IBodyData original, bool useTransformerForBodyAsFile)
{
string transformedBodyAsFilename = transformerContext.ParseAndRender(original.BodyAsFile!, model);
var transformedBodyAsFilename = transformerContext.ParseAndRender(original.BodyAsFile!, model);
if (!useTransformerForBodyAsFile)
{
@@ -358,7 +358,7 @@ internal class Transformer : ITransformer
};
}
string text = transformerContext.FileSystemHandler.ReadResponseBodyAsString(transformedBodyAsFilename);
var text = transformerContext.FileSystemHandler.ReadResponseBodyAsString(transformedBodyAsFilename);
return new BodyData
{
DetectedBodyType = BodyType.String,

View File

@@ -602,22 +602,21 @@ public class ResponseWithTransformerTests
Check.That(response.Message.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)
[Fact]
public async Task Response_ProvideResponse_Transformer_WithBodyAsFile_And_TransformContentFromBodyAsFile()
{
// Assign
var filesystemHandlerMock = new Mock<IFileSystemHandler>(MockBehavior.Strict);
filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny<string>())).Returns("<xml MyUniqueNumber=\"{{request.query.MyUniqueNumber}}\"></xml>");
filesystemHandlerMock
.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny<string>()))
.Returns("<xml MyUniqueNumber=\"{{request.query.MyUniqueNumber}}\"></xml>");
_settings.FileSystemHandler = filesystemHandlerMock.Object;
var request = new RequestMessage(new UrlDetails("http://localhost/foo?MyUniqueNumber=1"), "GET", ClientIp);
var responseBuilder = Response.Create()
.WithTransformer(transformerType, true)
.WithTransformer(transformContentFromBodyAsFile: true)
.WithBodyFromFile(@"c:\\{{request.query.MyUniqueNumber}}\\test.xml");
// Act

View File

@@ -0,0 +1,98 @@
// Copyright © WireMock.Net
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using FluentAssertions;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using Xunit;
namespace WireMock.Net.Tests;
public partial class WireMockServerTests
{
private const string RequestXml =
"""
<xml>
<Contact FirstName = "Stef" />
</xml>
""";
private readonly string _responseFilePath = Path.Combine(Environment.CurrentDirectory, "__admin", "mappings", "responseWithTransformer.xml");
[Fact]
public async Task WireMockServer_WithTransformer_WithBody_ShouldWork()
{
// Arrange
using var server = WireMockServer.Start();
server
.WhenRequest(req => req
.WithPath("/withbody")
.UsingPost())
.ThenRespondWith(rsp => rsp
.WithSuccess()
.WithBody(File.ReadAllText(_responseFilePath))
.WithTransformer());
// Act
var response = await GetResponseAsync(server, "/withbody");
// Assert
response.Should().Contain("Hello, Stef!");
}
[Fact]
public async Task WireMockServer_WithTransformerBefore_WithBodyFromFile_ShouldWork()
{
// Arrange
using var server = WireMockServer.Start();
server
.WhenRequest(req => req
.WithPath("/withbodyfromfile")
.UsingPost())
.ThenRespondWith(rsp => rsp
.WithSuccess()
.WithTransformer(transformContentFromBodyAsFile: true)
.WithBodyFromFile(_responseFilePath));
// Act
var response = await GetResponseAsync(server, "/withbodyfromfile");
// Assert
response.Should().Contain("Hello, Stef!");
}
[Fact]
public void WireMockServer_WithTransformerAfter_WithBodyFromFile_ShouldThrow()
{
// Act
var act = () =>
{
using var server = WireMockServer.Start();
server
.WhenRequest(req => req
.WithPath("/")
.UsingPost())
.ThenRespondWith(rsp => rsp
.WithSuccess()
.WithBodyFromFile(_responseFilePath)
.WithTransformer(transformContentFromBodyAsFile: true));
};
// Assert
act.Should().Throw<InvalidOperationException>().WithMessage("WithTransformer should be used before WithBodyFromFile.");
}
private static async Task<string> GetResponseAsync(WireMockServer server, string relativePath)
{
using HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(server.Urls[0]);
using var requestContent = new StringContent(RequestXml);
using var responseMsg = await httpClient.PostAsync(relativePath, requestContent);
return await responseMsg.Content.ReadAsStringAsync();
}
}

View File

@@ -0,0 +1,3 @@
<xml>
<hello>Hello, {{XPath.Evaluate request.body "//*[local-name()='Contact']/@FirstName"}}!</hello>
</xml>