From 69dd1cb007a57b5431600257021c5867fa5ecc98 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 4 Jan 2022 21:25:32 +0100 Subject: [PATCH] revert --- .../MainApp.cs | 2 +- .../Types/ReplaceNodeOption.cs | 57 +++++++++------- .../ITransformResponseBuilder.cs | 2 +- src/WireMock.Net/ResponseBuilders/Response.cs | 2 +- .../Serialization/WebhookMapper.cs | 2 +- .../Server/WireMockServer.Admin.cs | 2 +- src/WireMock.Net/Transformers/Transformer.cs | 33 ++++----- src/WireMock.Net/Util/StringUtils.cs | 42 ++++++++++++ .../ResponseWithHandlebarsRandomTests.cs | 15 ++-- .../ResponseWithTransformerTests.cs | 68 ++++++++++++++++--- 10 files changed, 159 insertions(+), 66 deletions(-) create mode 100644 src/WireMock.Net/Util/StringUtils.cs diff --git a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs index ffa825154..56d380dd7 100644 --- a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs +++ b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs @@ -357,7 +357,7 @@ public static void Run() .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(TransformerType.Handlebars, true, ReplaceNodeOption.Bool | ReplaceNodeOption.Integer) + .WithTransformer(TransformerType.Handlebars, true, ReplaceNodeOption.Default) .WithDelay(TimeSpan.FromMilliseconds(100)) ); diff --git a/src/WireMock.Net.Abstractions/Types/ReplaceNodeOption.cs b/src/WireMock.Net.Abstractions/Types/ReplaceNodeOption.cs index 41a830959..80514ea55 100644 --- a/src/WireMock.Net.Abstractions/Types/ReplaceNodeOption.cs +++ b/src/WireMock.Net.Abstractions/Types/ReplaceNodeOption.cs @@ -8,29 +8,38 @@ namespace WireMock.Types [Flags] public enum ReplaceNodeOption { - /// - /// Don't replace any of the below types. - /// - None = 0, - - /// - /// Replace boolean string value to a real boolean value. (This is used by default to maintain backward compatibility.) - /// - Bool = 0b00000001, - - /// - /// Replace integer string value to a real integer value. - /// - Integer = 0b00000010, - - /// - /// Replace long string value to a real long value. - /// - Long = 0b00000100, - - /// - /// Replace all string values to a real values. - /// - All = Bool | Integer | Long + Default = 0, + //None = 0, + + //StripQuotes = 0b00001000, + + //AddQuotes = 0b00010000, + + //Keep = 0b00000010, + + ///// + ///// Don't replace any of the below types. + ///// + //None = 0, + + ///// + ///// Replace boolean string value to a real boolean value. (This is used by default to maintain backward compatibility.) + ///// + //Bool = 0b00000001, + + ///// + ///// Replace integer string value to a real integer value. + ///// + //Integer = 0b00000010, + + ///// + ///// Replace long string value to a real long value. + ///// + //Long = 0b00000100, + + ///// + ///// Replace all string values to a real values. + ///// + //All = Bool | Integer | Long } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs index 1fd825a31..f8c2f06f1 100644 --- a/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/ITransformResponseBuilder.cs @@ -29,6 +29,6 @@ public interface ITransformResponseBuilder : IDelayResponseBuilder /// /// The . /// - IResponseBuilder WithTransformer(TransformerType transformerType = TransformerType.Handlebars, bool transformContentFromBodyAsFile = false, ReplaceNodeOption option = ReplaceNodeOption.Bool); + IResponseBuilder WithTransformer(TransformerType transformerType = TransformerType.Handlebars, bool transformContentFromBodyAsFile = false, ReplaceNodeOption option = ReplaceNodeOption.Default); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/Response.cs b/src/WireMock.Net/ResponseBuilders/Response.cs index 67a3b87c8..e3aa31e08 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.cs @@ -349,7 +349,7 @@ public IResponseBuilder WithTransformer(ReplaceNodeOption option) #pragma warning disable CS1574 /// #pragma warning restore CS1574 - public IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false, ReplaceNodeOption option = ReplaceNodeOption.Bool) + public IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false, ReplaceNodeOption option = ReplaceNodeOption.Default) { UseTransformer = true; TransformerType = transformerType; diff --git a/src/WireMock.Net/Serialization/WebhookMapper.cs b/src/WireMock.Net/Serialization/WebhookMapper.cs index 0ebe90470..03ce8f159 100644 --- a/src/WireMock.Net/Serialization/WebhookMapper.cs +++ b/src/WireMock.Net/Serialization/WebhookMapper.cs @@ -34,7 +34,7 @@ public static IWebhook Map(WebhookModel model) if (!Enum.TryParse(model.Request.TransformerReplaceNodeOption, out var option)) { - option = ReplaceNodeOption.Bool; + option = ReplaceNodeOption.Default; } webhook.Request.TransformerReplaceNodeOption = option; diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs index f2ec1472e..d56087be2 100644 --- a/src/WireMock.Net/Server/WireMockServer.Admin.cs +++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs @@ -788,7 +788,7 @@ private IResponseBuilder InitResponseBuilder(ResponseModel responseModel) if (!Enum.TryParse(responseModel.TransformerReplaceNodeOption, out var option)) { - option = ReplaceNodeOption.Bool; + option = ReplaceNodeOption.Default; } responseBuilder = responseBuilder.WithTransformer( transformerType, diff --git a/src/WireMock.Net/Transformers/Transformer.cs b/src/WireMock.Net/Transformers/Transformer.cs index d4ed932ae..9a2749af0 100644 --- a/src/WireMock.Net/Transformers/Transformer.cs +++ b/src/WireMock.Net/Transformers/Transformer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using WireMock.Types; using WireMock.Util; @@ -193,39 +194,35 @@ private static void WalkNode(ITransformerContext handlebarsContext, ReplaceNodeO return; } - string transformedString = handlebarsContext.ParseAndRender(stringValue, model); - if (!string.Equals(stringValue, transformedString)) + string transformed = handlebarsContext.ParseAndRender(stringValue, model); + if (!string.Equals(stringValue, transformed)) { - ReplaceNodeValue(option, node, transformedString); + ReplaceNodeValue(option, node, transformed); } break; } } - private static void ReplaceNodeValue(ReplaceNodeOption option, JToken node, string stringValue) + private static void ReplaceNodeValue(ReplaceNodeOption option, JToken node, string transformedString) { - if (option.HasFlag(ReplaceNodeOption.Bool) && bool.TryParse(stringValue, out bool valueAsBoolean)) + StringUtils.TryParseQuotedString(transformedString, out var result, out _); + bool valueAsBoolean; + if (bool.TryParse(result, out valueAsBoolean) || bool.TryParse(transformedString, out valueAsBoolean)) { node.Replace(valueAsBoolean); return; } - if (option.HasFlag(ReplaceNodeOption.Integer) && int.TryParse(stringValue, out int valueAsInteger)) + JToken value; + try { - node.Replace(valueAsInteger); - return; - } - - if (option.HasFlag(ReplaceNodeOption.Long) && long.TryParse(stringValue, out long valueAsLong)) - { - node.Replace(valueAsLong); - return; + // Try to convert this string into a JsonObject + value = JToken.Parse(transformedString); } - - if (!JsonUtils.TryParseAsComplexObject(stringValue, out JToken value)) + catch (JsonException) { - // Just keep string value and convert to JToken - value = stringValue; + // Ignore JsonException and just keep string value and convert to JToken + value = transformedString; } node.Replace(value); diff --git a/src/WireMock.Net/Util/StringUtils.cs b/src/WireMock.Net/Util/StringUtils.cs new file mode 100644 index 000000000..18c59853b --- /dev/null +++ b/src/WireMock.Net/Util/StringUtils.cs @@ -0,0 +1,42 @@ +using System.Linq; +using System.Text.RegularExpressions; + +namespace WireMock.Util +{ + internal static class StringUtils + { + public static bool TryParseQuotedString(string value, out string result, out char quote) + { + result = null; + quote = '\0'; + + if (value == null || value.Length < 2) + { + return false; + } + + quote = value[0]; // This can be single or a double quote + if (quote != '"' && quote != '\'') + { + return false; + } + + if (value.Last() != quote) + { + return false; + } + + try + { + result = Regex.Unescape(value.Substring(1, value.Length - 2)); + return true; + } + catch + { + // Ignore Exception, just continue and return false. + } + + return false; + } + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRandomTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRandomTests.cs index 9ab59816b..0a8626731 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRandomTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithHandlebarsRandomTests.cs @@ -16,15 +16,14 @@ public class ResponseWithHandlebarsRandomTests { 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"); + var filesystemHandlerMock = new Mock(MockBehavior.Strict); + filesystemHandlerMock.Setup(fs => fs.ReadResponseBodyAsString(It.IsAny())).Returns("abc"); - _settings.FileSystemHandler = _filesystemHandlerMock.Object; + _settings.FileSystemHandler = filesystemHandlerMock.Object; } [Fact] @@ -75,10 +74,10 @@ public async Task Response_ProvideResponseAsync_Handlebars_Random1_Boolean() } [Theory] - [InlineData(ReplaceNodeOption.None, JTokenType.String)] - [InlineData(ReplaceNodeOption.Bool, JTokenType.String)] - [InlineData(ReplaceNodeOption.Integer, JTokenType.Integer)] - [InlineData(ReplaceNodeOption.Bool | ReplaceNodeOption.Integer, JTokenType.Integer)] + [InlineData(ReplaceNodeOption.Default, JTokenType.Integer)] + //[InlineData(ReplaceNodeOption.Bool, JTokenType.String)] + //[InlineData(ReplaceNodeOption.Integer, JTokenType.Integer)] + //[InlineData(ReplaceNodeOption.Bool | ReplaceNodeOption.Integer, JTokenType.Integer)] public async Task Response_ProvideResponseAsync_Handlebars_Random1_Integer(ReplaceNodeOption option, JTokenType expected) { // Assign diff --git a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithTransformerTests.cs b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithTransformerTests.cs index 401253973..c960f74a7 100644 --- a/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithTransformerTests.cs +++ b/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithTransformerTests.cs @@ -385,15 +385,52 @@ public async Task Response_ProvideResponse_Transformer_WithBodyAsJson_ResultAsOb Check.That(JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson)).Equals("{\"x\":\"test /foo_object\"}"); } + //[Theory] + //[InlineData(TransformerType.Handlebars, "a")] + //[InlineData(TransformerType.Handlebars, "42")] + //[InlineData(TransformerType.Handlebars, "{")] + //[InlineData(TransformerType.Handlebars, "]")] + //[InlineData(TransformerType.Handlebars, " ")] + //public async Task Response_ProvideResponse_Transformer_WithBodyAsJsonWithExtraQuotes_AndSpecialOption_MakesAString_ResultAsObject(TransformerType transformerType, string text) + //{ + // string jsonString = $"{{ \"x\": \"{text}\" }}"; + // var bodyData = new BodyData + // { + // BodyAsJson = JsonConvert.DeserializeObject(jsonString), + // DetectedBodyType = BodyType.Json, + // Encoding = Encoding.UTF8 + // }; + // var request = new RequestMessage(new UrlDetails("http://localhost/foo_object"), "POST", ClientIp, bodyData); + + // var responseBuilder = Response.Create() + // .WithBodyAsJson(new { text = "\"{{request.bodyAsJson.x}}\"" }) + // .WithTransformer(transformerType, false, ReplaceNodeOption.Default); + + // // Act + // var response = await responseBuilder.ProvideResponseAsync(request, _settings).ConfigureAwait(false); + + // // Assert + // JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson).Should().Be($"{{\"text\":\"{text}\"}}"); + //} + [Theory] - [InlineData(TransformerType.Handlebars, "a")] - [InlineData(TransformerType.Handlebars, "42")] - [InlineData(TransformerType.Handlebars, "{")] - [InlineData(TransformerType.Handlebars, "]")] - [InlineData(TransformerType.Handlebars, " ")] - public async Task Response_ProvideResponse_Transformer_WithBodyAsJsonWithText_ResultAsObject(TransformerType transformerType, string text) + [InlineData(TransformerType.Handlebars, "\"\"", "\"\"")] + [InlineData(TransformerType.Handlebars, "\"a\"", "\"a\"")] + [InlineData(TransformerType.Handlebars, "\" \"", "\" \"")] + [InlineData(TransformerType.Handlebars, "\"'\"", "\"'\"")] + [InlineData(TransformerType.Handlebars, "\"false\"", "false")] // bool is special + [InlineData(TransformerType.Handlebars, "false", "false")] + [InlineData(TransformerType.Handlebars, "\"true\"", "true")] // bool is special + [InlineData(TransformerType.Handlebars, "true", "true")] + [InlineData(TransformerType.Handlebars, "\"-42\"", "-42")] // todo + [InlineData(TransformerType.Handlebars, "-42", "-42")] + [InlineData(TransformerType.Handlebars, "\"2147483647\"", "2147483647")] // todo + [InlineData(TransformerType.Handlebars, "2147483647", "2147483647")] + [InlineData(TransformerType.Handlebars, "\"9223372036854775807\"", "9223372036854775807")] // todo + [InlineData(TransformerType.Handlebars, "9223372036854775807", "9223372036854775807")] + public async Task Response_ProvideResponse_Transformer_WithBodyAsJson_And_ReplaceNodeOptionKeep(TransformerType transformerType, string value, string expected) { - string jsonString = $"{{ \"x\": \"{text}\" }}"; + string jsonString = $"{{ \"x\": {value} }}"; var bodyData = new BodyData { BodyAsJson = JsonConvert.DeserializeObject(jsonString), @@ -404,22 +441,31 @@ public async Task Response_ProvideResponse_Transformer_WithBodyAsJsonWithText_Re var responseBuilder = Response.Create() .WithBodyAsJson(new { text = "{{request.bodyAsJson.x}}" }) - .WithTransformer(transformerType); + .WithTransformer(transformerType, false, ReplaceNodeOption.Default); // Act var response = await responseBuilder.ProvideResponseAsync(request, _settings).ConfigureAwait(false); // Assert - JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson).Should().Be($"{{\"text\":\"{text}\"}}"); + JsonConvert.SerializeObject(response.Message.BodyData.BodyAsJson).Should().Be($"{{\"text\":{expected}}}"); } [Theory] + [InlineData(TransformerType.Handlebars, "\"\"", "\"\"")] + [InlineData(TransformerType.Handlebars, "\"a\"", "\"a\"")] + [InlineData(TransformerType.Handlebars, "\" \"", "\" \"")] + [InlineData(TransformerType.Handlebars, "\"'\"", "\"'\"")] + [InlineData(TransformerType.Handlebars, "\"false\"", "false")] // bool is special [InlineData(TransformerType.Handlebars, "false", "false")] + [InlineData(TransformerType.Handlebars, "\"true\"", "true")] // bool is special [InlineData(TransformerType.Handlebars, "true", "true")] + [InlineData(TransformerType.Handlebars, "\"-42\"", "\"-42\"")] [InlineData(TransformerType.Handlebars, "-42", "\"-42\"")] + [InlineData(TransformerType.Handlebars, "\"2147483647\"", "\"2147483647\"")] [InlineData(TransformerType.Handlebars, "2147483647", "\"2147483647\"")] + [InlineData(TransformerType.Handlebars, "\"9223372036854775807\"", "\"9223372036854775807\"")] [InlineData(TransformerType.Handlebars, "9223372036854775807", "\"9223372036854775807\"")] - public async Task Response_ProvideResponse_Transformer_WithBodyAsJsonWithPrimitive_ResultAsObject(TransformerType transformerType, string value, string expected) + public async Task Response_ProvideResponse_Transformer_WithBodyAsJsonWithExtraQuotes_AlwaysMakesString(TransformerType transformerType, string value, string expected) { string jsonString = $"{{ \"x\": {value} }}"; var bodyData = new BodyData @@ -431,7 +477,7 @@ public async Task Response_ProvideResponse_Transformer_WithBodyAsJsonWithPrimiti var request = new RequestMessage(new UrlDetails("http://localhost/foo_object"), "POST", ClientIp, bodyData); var responseBuilder = Response.Create() - .WithBodyAsJson(new { text = "{{request.bodyAsJson.x}}" }) + .WithBodyAsJson(new { text = "\"{{request.bodyAsJson.x}}\"" }) .WithTransformer(transformerType); // Act