diff --git a/src/Handlebars.Net.Helpers.Core/Handlebars.Net.Helpers.Core.csproj b/src/Handlebars.Net.Helpers.Core/Handlebars.Net.Helpers.Core.csproj index f5e8612..b3c725b 100644 --- a/src/Handlebars.Net.Helpers.Core/Handlebars.Net.Helpers.Core.csproj +++ b/src/Handlebars.Net.Helpers.Core/Handlebars.Net.Helpers.Core.csproj @@ -34,5 +34,4 @@ - \ No newline at end of file diff --git a/src/Handlebars.Net.Helpers.Core/Utils/SimpleJsonUtils.cs b/src/Handlebars.Net.Helpers.Core/Utils/SimpleJsonUtils.cs new file mode 100644 index 0000000..4a001fd --- /dev/null +++ b/src/Handlebars.Net.Helpers.Core/Utils/SimpleJsonUtils.cs @@ -0,0 +1,16 @@ +using HandlebarsDotNet.Helpers.Json; + +namespace HandlebarsDotNet.Helpers.Utils; + +public static class SimpleJsonUtils +{ + public static string? SerializeObject(object? value) + { + return SimpleJson.SerializeObject(value); + } + + public static T? DeserializeObject(string? json) + { + return SimpleJson.DeserializeObject(json); + } +} \ No newline at end of file diff --git a/src/Handlebars.Net.Helpers.Random/Handlebars.Net.Helpers.Random.csproj b/src/Handlebars.Net.Helpers.Random/Handlebars.Net.Helpers.Random.csproj index 0dead86..7acb2eb 100644 --- a/src/Handlebars.Net.Helpers.Random/Handlebars.Net.Helpers.Random.csproj +++ b/src/Handlebars.Net.Helpers.Random/Handlebars.Net.Helpers.Random.csproj @@ -12,6 +12,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Handlebars.Net.Helpers.Random/Helpers/RandomHelpers.cs b/src/Handlebars.Net.Helpers.Random/Helpers/RandomHelpers.cs index 3aa4030..3e3d0e3 100644 --- a/src/Handlebars.Net.Helpers.Random/Helpers/RandomHelpers.cs +++ b/src/Handlebars.Net.Helpers.Random/Helpers/RandomHelpers.cs @@ -4,10 +4,12 @@ using HandlebarsDotNet.Helpers.Attributes; using HandlebarsDotNet.Helpers.Enums; using HandlebarsDotNet.Helpers.Helpers; +using HandlebarsDotNet.Helpers.Models; using HandlebarsDotNet.Helpers.Parsers; using RandomDataGenerator.FieldOptions; using RandomDataGenerator.Randomizers; +// ReSharper disable once CheckNamespace namespace HandlebarsDotNet.Helpers; internal class RandomHelpers : BaseHelpers, IHelpers @@ -19,14 +21,39 @@ public RandomHelpers(IHandlebars context) : base(context) /// /// For backwards compatibility with WireMock.Net /// - [HandlebarsWriter(WriterType.Value, "Random")] + [HandlebarsWriter(WriterType.String, "Random")] public object? Random(IDictionary hash) { return Generate(hash); } + /// + /// For backwards compatibility with WireMock.Net + /// + [HandlebarsWriter(WriterType.String, "RandomKeepType")] + public string? RandomKeepType(IDictionary hash) + { + return GenerateAsOutputWithType(hash); + } + [HandlebarsWriter(WriterType.Value)] public object? Generate(IDictionary hash) + { + var keepType = hash.TryGetValue("KeepType", out var value) && value is true; + + return GenerateInternal(hash, keepType); + } + + /// + /// It returns a JSON string. + /// + [HandlebarsWriter(WriterType.String)] + public string? GenerateAsOutputWithType(IDictionary hash) + { + return GenerateInternal(hash, true) is not OutputWithType outputWithType ? null : outputWithType.Serialize(); + } + + private object? GenerateInternal(IDictionary hash, bool outputWithType) { var fieldOptions = GetFieldOptionsFromHash(hash); dynamic randomizer = RandomizerFactory.GetRandomizerAsDynamic(fieldOptions); @@ -35,34 +62,52 @@ public RandomHelpers(IHandlebars context) : base(context) if (fieldOptions is IFieldOptionsDateTime) { DateTime? date = randomizer.Generate(); - return date?.ToString("s", Context.Configuration.FormatProvider); + return GetRandomValue(outputWithType, () => date?.ToString("s", Context.Configuration.FormatProvider), () => date); } // If the IFieldOptionsGuid defines Uppercase, use the 'GenerateAsString' method. if (fieldOptions is IFieldOptionsGuid fieldOptionsGuid) { - return fieldOptionsGuid.Uppercase ? randomizer.GenerateAsString() : randomizer.Generate(); + return GetRandomValue(outputWithType, + () => fieldOptionsGuid.Uppercase ? randomizer.GenerateAsString() : randomizer.Generate(), + () => randomizer.Generate() + ); } - return randomizer.Generate(); + return GetRandomValue(outputWithType, () => randomizer.Generate(), null); } private FieldOptionsAbstract GetFieldOptionsFromHash(IDictionary hash) { - if (hash.TryGetValue("Type", out var value) && value is string randomType) + if (!hash.TryGetValue("Type", out var value) || value is not string randomType) + { + throw new HandlebarsException("The Type argument is missing."); + } + + var newProperties = new Dictionary(); + foreach (var item in hash.Where(p => p.Key != "Type")) { - var newProperties = new Dictionary(); - foreach (var item in hash.Where(p => p.Key != "Type")) - { - bool convertObjectArrayToStringList = randomType == "StringList"; - var parsedArgumentValue = ArgumentsParser.Parse(Context, item.Value, convertObjectArrayToStringList); + var convertObjectArrayToStringList = randomType == "StringList"; + var parsedArgumentValue = ArgumentsParser.Parse(Context, item.Value, convertObjectArrayToStringList); + + newProperties.Add(item.Key, parsedArgumentValue); + } - newProperties.Add(item.Key, parsedArgumentValue); - } + return FieldOptionsFactory.GetFieldOptions(randomType, newProperties!); + } - return FieldOptionsFactory.GetFieldOptions(randomType, newProperties!); + private static object? GetRandomValue(bool outputWithType, Func funcNormal, Func? funcWithType) + { + object? value; + if (outputWithType && funcWithType != null) + { + value = funcWithType(); + } + else + { + value = funcNormal(); } - throw new HandlebarsException("The Type argument is missing."); + return outputWithType ? OutputWithType.Parse(value) : value; } } \ No newline at end of file diff --git a/src/Handlebars.Net.Helpers/HandlebarsHelpers.cs b/src/Handlebars.Net.Helpers/HandlebarsHelpers.cs index 2969552..0412afb 100644 --- a/src/Handlebars.Net.Helpers/HandlebarsHelpers.cs +++ b/src/Handlebars.Net.Helpers/HandlebarsHelpers.cs @@ -214,7 +214,12 @@ private static void RegisterValueHelper(IHandlebars handlebarsContext, object in { HandlebarsReturnWithOptionsHelper helper = (in HelperOptions options, in Context context, in Arguments arguments) => { - return InvokeMethod(passContext ? context : null, false, handlebarsContext, helperName, methodInfo, arguments, instance, options); + var value = InvokeMethod(passContext ? context : null, false, handlebarsContext, helperName, methodInfo, arguments, instance, options); + + var keepType = arguments.Hash.TryGetValue("KeepType", out var keepTypeValue) && + (keepTypeValue is true || keepTypeValue is string keepTypeAsString && string.Equals(keepTypeAsString, bool.TrueString, StringComparison.OrdinalIgnoreCase)); + + return keepType ? OutputWithType.Parse(value).Serialize() : value; }; handlebarsContext.RegisterHelper(helperName, helper); diff --git a/src/Handlebars.Net.Helpers/Models/OutputWithType.cs b/src/Handlebars.Net.Helpers/Models/OutputWithType.cs new file mode 100644 index 0000000..f840a8c --- /dev/null +++ b/src/Handlebars.Net.Helpers/Models/OutputWithType.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using HandlebarsDotNet.Helpers.Json; +using HandlebarsDotNet.Helpers.Utils; + +namespace HandlebarsDotNet.Helpers.Models; + +public class OutputWithType +{ + public object? Value { get; set; } + + public string? TypeName { get; set; } + + public string? FullTypeName { get; set; } + + public static OutputWithType Parse(object? value) + { + var typeName = value?.GetType().Name; + var fullTypeName = value?.GetType().FullName; + + if (value is IEnumerable array) + { + value = ArrayUtils.ToArray(array); + } + + return new OutputWithType + { + Value = value, + FullTypeName = fullTypeName, + TypeName = typeName + }; + } + + public override string ToString() + { + return Serialize() ?? string.Empty; + } + + public string? Serialize() + { + return SimpleJsonUtils.SerializeObject(this); + } + + public static OutputWithType Deserialize(string? json) + { + var jsonObject = SimpleJsonUtils.DeserializeObject(json); + + if (jsonObject == null) + { + throw new InvalidOperationException(); + } + + if (!TryGetValue(jsonObject, out var value)) + { + throw new MissingMemberException($"Property '{nameof(Value)}' is not found on type '{nameof(OutputWithType)}'."); + } + + if (!TryGetTypeName(jsonObject, out var typeName)) + { + throw new MissingMemberException($"Property '{nameof(TypeName)}' is not found on type '{nameof(OutputWithType)}'."); + } + + if (!TryGetFullTypeName(jsonObject, out var fullTypeName)) + { + throw new MissingMemberException($"Property '{nameof(FullTypeName)}' is not found on type '{nameof(OutputWithType)}'."); + } + + if (!TryGetType(fullTypeName, out var fullType)) + { + throw new TypeLoadException($"Unable to load Type with FullTypeName '{fullTypeName}'."); + } + + return new OutputWithType + { + Value = TryConvert(value, fullType, out var convertedValue) ? convertedValue : value, + TypeName = typeName, + FullTypeName = fullTypeName + }; + } + + public static bool TryDeserialize(string? json, [NotNullWhen(true)] out OutputWithType? outputWithType) + { + JsonObject? jsonObject; + try + { + jsonObject = SimpleJsonUtils.DeserializeObject(json); + } + catch + { + outputWithType = null; + return false; + } + + if (jsonObject != null && + TryGetValue(jsonObject, out var value) && + TryGetTypeName(jsonObject, out var typeName) && + TryGetFullTypeName(jsonObject, out var fullTypeName) && + TryGetType(fullTypeName, out var fullType) + ) + { + outputWithType = new OutputWithType + { + Value = TryConvert(value, fullType, out var convertedValue) ? convertedValue : value, + TypeName = typeName, + FullTypeName = fullTypeName + }; + return true; + } + + outputWithType = default; + return false; + } + + private static bool TryGetValue(JsonObject jsonObject, out object value) + { + return jsonObject.TryGetValue(nameof(Value), out value); + } + + private static bool TryGetTypeName(JsonObject jsonObject, [NotNullWhen(true)] out string? value) + { + if (jsonObject.TryGetValue(nameof(TypeName), out var typeName) && typeName is string typeNameAsString) + { + value = typeNameAsString; + return true; + } + + value = default; + return false; + } + + private static bool TryGetFullTypeName(JsonObject jsonObject, [NotNullWhen(true)] out string? value) + { + if (jsonObject.TryGetValue(nameof(FullTypeName), out var fullTypeName) && fullTypeName is string fullTypeNameAsString) + { + value = fullTypeNameAsString; + return true; + } + + value = default; + return false; + } + + private static bool TryGetType(string fullTypeName, [NotNullWhen(true)] out Type? type) + { + type = Type.GetType(fullTypeName) ?? Type.GetType($"{fullTypeName}, System"); + return type != null; + } + + private static bool TryConvert(object? value, Type fullType, [NotNullWhen(true)] out object? result) + { + try + { + if (fullType == typeof(Guid) && value is string guidAsString) + { + result = new Guid(guidAsString); + return true; + } + + if (fullType == typeof(Uri) && value is string uriAsString) + { + result = new Uri(uriAsString); + return true; + } + + if (fullType == typeof(TimeSpan) && value is JsonObject timeSpanAsJsonObject) + { + result = TimeSpan.FromTicks((long)timeSpanAsJsonObject["Ticks"]); + return true; + } + + if (fullType.IsArray && value is JsonArray jsonArray) + { + var elementType = fullType.GetElementType()!; + var newArray = Array.CreateInstance(elementType, jsonArray.Count); + for (var i = 0; i < jsonArray.Count; i++) + { + newArray.SetValue(Convert.ChangeType(jsonArray[i], elementType), i); + } + + result = newArray; + } + else + { + result = Convert.ChangeType(value, fullType); + } + + return true; + } + catch + { + result = default; + return false; + } + } +} \ No newline at end of file diff --git a/test/Handlebars.Net.Helpers.Tests/Helpers/RandomHelpersTests.cs b/test/Handlebars.Net.Helpers.Tests/Helpers/RandomHelpersTests.cs index 1d9cff5..88b13f3 100644 --- a/test/Handlebars.Net.Helpers.Tests/Helpers/RandomHelpersTests.cs +++ b/test/Handlebars.Net.Helpers.Tests/Helpers/RandomHelpersTests.cs @@ -1,5 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using FluentAssertions; +using HandlebarsDotNet.Helpers.Models; using Moq; using Xunit; @@ -18,7 +20,20 @@ public RandomHelpersTests() } [Fact] - public void Random() + public void Random_TypeIsMissing_Should_Throw() + { + // Arrange + var hash = new Dictionary(); + + // Act + Action action = () => _sut.Random(hash); + + // Assert + action.Should().Throw().Which.Message.Should().Be("The Type argument is missing."); + } + + [Fact] + public void Random_Integer() { // Arrange var hash = new Dictionary @@ -32,6 +47,27 @@ public void Random() var result = _sut.Random(hash); // Assert - (result as int?).Should().BeInRange(1000, 9999); + result.Should().BeOfType().Which.Should().BeInRange(1000, 9999); + } + + [Fact] + public void RandomAsOutputWithType_Integer() + { + // Arrange + var hash = new Dictionary + { + { "Type", "Integer" }, + { "Min", 1000 }, + { "Max", 9999 } + }; + + // Act + var result = _sut.RandomKeepType(hash); + + // Assert + var outputWithType = OutputWithType.Deserialize(result)!; + outputWithType.Value.Should().BeOfType().Which.Should().BeInRange(1000, 9999); + outputWithType.TypeName.Should().Be("Int32"); + outputWithType.FullTypeName.Should().Be("System.Int32"); } } \ No newline at end of file diff --git a/test/Handlebars.Net.Helpers.Tests/Models/OutputWithTypeTests.cs b/test/Handlebars.Net.Helpers.Tests/Models/OutputWithTypeTests.cs new file mode 100644 index 0000000..10ba41d --- /dev/null +++ b/test/Handlebars.Net.Helpers.Tests/Models/OutputWithTypeTests.cs @@ -0,0 +1,274 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using FluentAssertions; +using HandlebarsDotNet.Helpers.Models; +using Xunit; + +namespace HandlebarsDotNet.Helpers.Tests.Models; + +[ExcludeFromCodeCoverage] +public class OutputWithTypeTests +{ + [Fact] + public void Deserialize_ForString_ShouldReturnOutputWithType_WhenJsonIsValid() + { + // Arrange + var json = "{\"Value\":\"test\",\"TypeName\":\"String\",\"FullTypeName\":\"System.String\"}"; + + // Act + var result = OutputWithType.Deserialize(json); + + // Assert + result.Should().NotBeNull(); + result.Value.Should().BeOfType().And.Be("test"); + result.TypeName.Should().Be("String"); + result.FullTypeName.Should().Be("System.String"); + } + + [Fact] + public void Deserialize_ForInteger_ShouldReturnOutputWithType_WhenJsonIsValid() + { + // Arrange + var json = "{\"Value\":\"12345\",\"TypeName\":\"Int32\",\"FullTypeName\":\"System.Int32\"}"; + + // Act + var result = OutputWithType.Deserialize(json); + + result.Should().NotBeNull(); + result.Value.Should().BeOfType().And.Be(12345); + result.TypeName.Should().Be("Int32"); + result.FullTypeName.Should().Be("System.Int32"); + } + + [Fact] + public void Deserialize_WhenValueCannotBeConvertedToFullType_ShouldKeepOriginalValue() + { + // Arrange + var json = "{\"Value\":\"test\",\"TypeName\":\"Int32\",\"FullTypeName\":\"System.Int32\"}"; + + // Act + var result = OutputWithType.Deserialize(json); + + // Assert + result.Should().NotBeNull(); + result.Value.Should().BeOfType().And.Be("test"); + result.TypeName.Should().Be("Int32"); + result.FullTypeName.Should().Be("System.Int32"); + } + + [Fact] + public void Deserialize_ShouldThrowMissingMemberException_WhenValueIsMissing() + { + // Arrange + var json = "{\"TypeName\":\"String\",\"FullTypeName\":\"System.String\"}"; + + // Act + Action act = () => OutputWithType.Deserialize(json); + + // Assert + act.Should().Throw() + .WithMessage("*'Value'*"); + } + + [Fact] + public void Deserialize_ShouldThrowMissingMemberException_WhenTypeNameIsMissing() + { + // Arrange + var json = "{\"Value\":\"12345\",\"FullTypeName\":\"System.Int32\"}"; + + // Act + Action act = () => OutputWithType.Deserialize(json); + + // Assert + act.Should().Throw() + .WithMessage("*'TypeName'*"); + } + + [Fact] + public void Deserialize_ShouldThrowMissingMemberException_WhenFullTypeNameIsMissing() + { + // Arrange + var json = "{\"Value\":\"test\",\"TypeName\":\"String\"}"; + + // Act + Action act = () => OutputWithType.Deserialize(json); + + // Assert + act.Should().Throw() + .WithMessage("*'FullTypeName'*"); + } + + [Fact] + public void Deserialize_ShouldException_WhenFullTypeNameIsInvalid() + { + // Arrange + var json = "{\"Value\":\"test\",\"TypeName\":\"Int32\",\"FullTypeName\":\"abc\"}"; + + // Act + Action act = () => OutputWithType.Deserialize(json); + + // Assert + act.Should().Throw() + .WithMessage("Unable to load Type with FullTypeName 'abc'."); + } + + [Fact] + public void Deserialize_ShouldThrowInvalidOperationException_WhenJsonIsNull() + { + // Act + Action act = () => OutputWithType.Deserialize(null); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void Deserialize_ShouldThrowJsonException_WhenJsonIsInvalid() + { + // Act + Action act = () => OutputWithType.Deserialize("invalid json"); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TryDeserialize_ForString_ShouldReturnTrue_WhenJsonIsValid() + { + // Arrange + var json = "{\"Value\":\"test\",\"TypeName\":\"String\",\"FullTypeName\":\"System.String\"}"; + + // Act + var result = OutputWithType.TryDeserialize(json, out var output); + + // Assert + result.Should().BeTrue(); + output!.Value.Should().NotBeNull().And.BeOfType().And.Be("test"); + output.TypeName.Should().Be("String"); + output.FullTypeName.Should().Be("System.String"); + } + + [Fact] + public void TryDeserialize_ForInteger_ShouldReturnTrue() + { + // Arrange + var json = "{\"Value\":\"12345\",\"TypeName\":\"Int32\",\"FullTypeName\":\"System.Int32\"}"; + + // Act + var result = OutputWithType.TryDeserialize(json, out var output); + + result.Should().BeTrue(); + output!.Value.Should().BeOfType().And.Be(12345); + output.TypeName.Should().Be("Int32"); + output.FullTypeName.Should().Be("System.Int32"); + } + + [Fact] + public void TryDeserialize_ForUri_ShouldReturnTrue() + { + // Arrange + var json = "{\"Value\":\"https://localhost\",\"TypeName\":\"Uri\",\"FullTypeName\":\"System.Uri\"}"; + + // Act + var result = OutputWithType.TryDeserialize(json, out var output); + + result.Should().BeTrue(); + output!.Value.Should().BeOfType().And.Be(new Uri("https://localhost")); + output.TypeName.Should().Be("Uri"); + output.FullTypeName.Should().Be("System.Uri"); + } + + [Fact] + public void TryDeserialize_WhenValueCannotBeConvertedToFullType_ShouldReturnTrue_And_KeepOriginalValue() + { + // Arrange + var json = "{\"Value\":\"test\",\"TypeName\":\"Int32\",\"FullTypeName\":\"System.Int32\"}"; + + // Act + var result = OutputWithType.TryDeserialize(json, out var output); + + // Assert + result.Should().BeTrue(); + output!.Value.Should().BeOfType().And.Be("test"); + output.TypeName.Should().Be("Int32"); + output.FullTypeName.Should().Be("System.Int32"); + } + + [Fact] + public void TryDeserialize_ShouldReturnFalse_WhenValueIsMissing() + { + // Arrange + var json = "{\"TypeName\":\"String\",\"FullTypeName\":\"System.String\"}"; + + // Act + var result = OutputWithType.TryDeserialize(json, out var output); + + // Assert + result.Should().BeFalse(); + output.Should().BeNull(); + } + + [Fact] + public void TryDeserialize_ShouldReturnFalse_WhenTypeNameIsMissing() + { + // Arrange + var json = "{\"Value\":\"test\",\"FullTypeName\":\"System.String\"}"; + + // Act + var result = OutputWithType.TryDeserialize(json, out var output); + + // Assert + result.Should().BeFalse(); + output.Should().BeNull(); + } + + [Fact] + public void TryDeserialize_ShouldReturnFalse_WhenFullTypeNameIsMissing() + { + // Arrange + var json = "{\"Value\":\"test\",\"TypeName\":\"String\"}"; + + // Act + var result = OutputWithType.TryDeserialize(json, out var output); + + // Assert + result.Should().BeFalse(); + output.Should().BeNull(); + } + + [Fact] + public void TryDeserialize_ShouldReturnFalse_WhenFullTypeNameInvalid() + { + // Arrange + var json = "{\"Value\":\"test\",\"TypeName\":\"Int32\",\"FullTypeName\":\"abc\"}"; + + // Act + var result = OutputWithType.TryDeserialize(json, out var output); + + // Assert + result.Should().BeFalse(); + output.Should().BeNull(); + } + + [Fact] + public void TryDeserialize_ShouldReturnFalse_WhenJsonIsNull() + { + // Act + var result = OutputWithType.TryDeserialize(null, out var output); + + // Assert + result.Should().BeFalse(); + output.Should().BeNull(); + } + + [Fact] + public void TryDeserialize_ShouldReturnFalse_WhenJsonIsInvalid() + { + // Act + var result = OutputWithType.TryDeserialize("invalid json", out var output); + + // Assert + result.Should().BeFalse(); + output.Should().BeNull(); + } +} \ No newline at end of file diff --git a/test/Handlebars.Net.Helpers.Tests/Templates/RandomHelpersTemplateTests.cs b/test/Handlebars.Net.Helpers.Tests/Templates/RandomHelpersTemplateTests.cs index 242cb06..ea47c2c 100644 --- a/test/Handlebars.Net.Helpers.Tests/Templates/RandomHelpersTemplateTests.cs +++ b/test/Handlebars.Net.Helpers.Tests/Templates/RandomHelpersTemplateTests.cs @@ -1,5 +1,7 @@ -using FluentAssertions; +using System; +using FluentAssertions; using HandlebarsDotNet.Helpers.Enums; +using HandlebarsDotNet.Helpers.Models; using Xunit; namespace HandlebarsDotNet.Helpers.Tests.Templates; @@ -15,6 +17,51 @@ public RandomHelpersTemplateTests() HandlebarsHelpers.Register(_handlebarsContext, Category.Random); } + [Fact] + public void Random_ForWireMock() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random Type=\"Integer\" Min=1000 Max=9999}}"); + + // Act + var result = action(""); + + // Assert + int.Parse(result).Should().BeInRange(1000, 9999); + } + + [Fact] + public void Random_ForWireMock_KeepTypeTrue() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random KeepType=true Type=\"Integer\" Min=1000 Max=9999}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType().Which.Should().BeInRange(1000, 9999); + outputWithType.TypeName.Should().Be("Int32"); + outputWithType.FullTypeName.Should().Be("System.Int32"); + } + + [Fact] + public void RandomKeepType_ForWireMock() + { + // Arrange + var action = _handlebarsContext.Compile("{{RandomKeepType Type=\"Integer\" Min=1000 Max=9999}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType().Which.Should().BeInRange(1000, 9999); + outputWithType.TypeName.Should().Be("Int32"); + outputWithType.FullTypeName.Should().Be("System.Int32"); + } + [Fact] public void Random_Integer() { @@ -64,6 +111,182 @@ public void Random_StringList() var result = action(""); // Assert - result.Should().NotBeEmpty("a"); + result.Should().NotBeNullOrEmpty(); + } + + [Fact] + public void Random_StringList_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"StringList\" Values=[\"a\", \"b\", \"c\"]}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType().Which.Should().NotBeNullOrEmpty(); + outputWithType.TypeName.Should().Be("String"); + outputWithType.FullTypeName.Should().Be("System.String"); + } + + [Fact] + public void Random_Integer_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"Integer\" Min=1000 Max=9999 }}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType().Which.Should().BeInRange(1000, 9999); + outputWithType.TypeName.Should().Be("Int32"); + outputWithType.FullTypeName.Should().Be("System.Int32"); + } + + [Fact] + public void Random_Guid_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"Guid\" }}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType(); + outputWithType.TypeName.Should().Be("Guid"); + outputWithType.FullTypeName.Should().Be("System.Guid"); + } + + [Fact] + public void Random_City_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"City\"}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType().Which.Should().NotBeNullOrEmpty(); + outputWithType.TypeName.Should().Be("String"); + outputWithType.FullTypeName.Should().Be("System.String"); + } + + [Fact] + public void Random_Boolean_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"Boolean\"}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType(); + outputWithType.TypeName.Should().Be("Boolean"); + outputWithType.FullTypeName.Should().Be("System.Boolean"); + } + + [Fact] + public void Random_Byte_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"Byte\"}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType().Which.Should().BeInRange(byte.MinValue, byte.MaxValue); + outputWithType.TypeName.Should().Be("Byte"); + outputWithType.FullTypeName.Should().Be("System.Byte"); + } + + [Fact] + public void Random_Bytes_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"Bytes\" Min=1 Max=9 }}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType().Which.Should().NotBeNullOrEmpty(); + outputWithType.TypeName.Should().Be("Byte[]"); + outputWithType.FullTypeName.Should().Be("System.Byte[]"); + } + + [Fact] + public void Random_Double_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"Double\"}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType(); + outputWithType.TypeName.Should().Be("Double"); + outputWithType.FullTypeName.Should().Be("System.Double"); + } + + [Fact] + public void Random_Float_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"Float\"}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType(); + outputWithType.TypeName.Should().Be("Single"); + outputWithType.FullTypeName.Should().Be("System.Single"); + } + + [Fact] + public void Random_DateTime_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"DateTime\"}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType(); + outputWithType.TypeName.Should().Be("DateTime"); + outputWithType.FullTypeName.Should().Be("System.DateTime"); + } + + [Fact] + public void Random_TimeSpan_OutputWithType() + { + // Arrange + var action = _handlebarsContext.Compile("{{Random.GenerateAsOutputWithType Type=\"TimeSpan\"}}"); + + // Act + var result = action(""); + + // Assert + var outputWithType = OutputWithType.Deserialize(result); + outputWithType.Value.Should().BeOfType(); + outputWithType.TypeName.Should().Be("TimeSpan"); + outputWithType.FullTypeName.Should().Be("System.TimeSpan"); } } \ No newline at end of file