diff --git a/src/WireMock.Net.Minimal/Serialization/MappingSerializer.cs b/src/WireMock.Net.Minimal/Serialization/MappingSerializer.cs new file mode 100644 index 00000000..577caffa --- /dev/null +++ b/src/WireMock.Net.Minimal/Serialization/MappingSerializer.cs @@ -0,0 +1,49 @@ +// Copyright © WireMock.Net + +using System; +using JsonConverter.Abstractions; +using Newtonsoft.Json.Linq; +#if NETSTANDARD2_0_OR_GREATER || NETCOREAPP3_1_OR_GREATER || NET6_0_OR_GREATER || NET461 +using System.Text.Json; +#endif + +namespace WireMock.Serialization; + +internal class MappingSerializer(IJsonConverter jsonConverter) +{ + internal T[] DeserializeJsonToArray(string value) + { + return DeserializeObjectToArray(jsonConverter.Deserialize(value)!); + } + + internal static T[] DeserializeObjectToArray(object value) + { + if (value is JArray jArray) + { + return jArray.ToObject()!; + } + + if (value is JObject jObject) + { + var singleResult = jObject.ToObject(); + return [singleResult!]; + } + +#if NETSTANDARD2_0_OR_GREATER || NETCOREAPP3_1_OR_GREATER || NET6_0_OR_GREATER || NET461 + if (value is JsonElement jElement) + { + if (jElement.ValueKind == JsonValueKind.Array) + { + return jElement.Deserialize()!; + } + + if (jElement.ValueKind == JsonValueKind.Object) + { + var singleResult = jElement.Deserialize(); + return [singleResult!]; + } + } +#endif + throw new InvalidOperationException("Cannot deserialize the provided value to an array or object."); + } +} \ No newline at end of file diff --git a/src/WireMock.Net.Minimal/WireMock.Net.Minimal.csproj b/src/WireMock.Net.Minimal/WireMock.Net.Minimal.csproj index 6d245c53..0708611b 100644 --- a/src/WireMock.Net.Minimal/WireMock.Net.Minimal.csproj +++ b/src/WireMock.Net.Minimal/WireMock.Net.Minimal.csproj @@ -118,11 +118,13 @@ + + diff --git a/test/WireMock.Net.Tests/Serialization/MappingSerializerTests.cs b/test/WireMock.Net.Tests/Serialization/MappingSerializerTests.cs new file mode 100644 index 00000000..b50ee74e --- /dev/null +++ b/test/WireMock.Net.Tests/Serialization/MappingSerializerTests.cs @@ -0,0 +1,338 @@ +// Copyright © WireMock.Net + +using System; +using FluentAssertions; +using JsonConverter.Newtonsoft.Json; +using WireMock.Admin.Mappings; +using WireMock.Serialization; +using Xunit; +#if NET8_0_OR_GREATER +using JsonConverter.System.Text.Json; +#endif + +namespace WireMock.Net.Tests.Serialization; + +public class MappingSerializerTests +{ + private const string SingleMappingJson = + """ + { + "Guid": "12345678-1234-1234-1234-123456789012", + "Priority": 1, + "Request": { + "Path": "/test" + }, + "Response": { + "StatusCode": 200 + } + } + """; + + private const string ArrayMappingJson = + """ + [ + { + "Guid": "12345678-1234-1234-1234-123456789012", + "Priority": 1, + "Request": { + "Path": "/test1" + }, + "Response": { + "StatusCode": 200 + } + }, + { + "Guid": "87654321-4321-4321-4321-210987654321", + "Priority": 2, + "Request": { + "Path": "/test2" + }, + "Response": { + "StatusCode": 404 + } + } + ] + """; + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithNewtonsoftJson_SingleObject_ShouldReturnArray() + { + // Arrange + var jsonConverter = new NewtonsoftJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + + // Act + var result = serializer.DeserializeJsonToArray(SingleMappingJson); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(1); + result[0].Guid.Should().Be(Guid.Parse("12345678-1234-1234-1234-123456789012")); + result[0].Priority.Should().Be(1); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithNewtonsoftJson_Array_ShouldReturnArray() + { + // Arrange + var jsonConverter = new NewtonsoftJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + + // Act + var result = serializer.DeserializeJsonToArray(ArrayMappingJson); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(2); + result[0].Guid.Should().Be(Guid.Parse("12345678-1234-1234-1234-123456789012")); + result[0].Priority.Should().Be(1); + result[1].Guid.Should().Be(Guid.Parse("87654321-4321-4321-4321-210987654321")); + result[1].Priority.Should().Be(2); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithNewtonsoftJson_EmptyArray_ShouldReturnEmptyArray() + { + // Arrange + var jsonConverter = new NewtonsoftJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var emptyArrayJson = "[]"; + + // Act + var result = serializer.DeserializeJsonToArray(emptyArrayJson); + + // Assert + result.Should().NotBeNull(); + result.Should().BeEmpty(); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithNewtonsoftJson_InvalidJson_ShouldThrowException() + { + // Arrange + var jsonConverter = new NewtonsoftJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var invalidJson = "not valid json"; + + // Act + Action act = () => serializer.DeserializeJsonToArray(invalidJson); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithNewtonsoftJson_ComplexMapping_ShouldDeserializeCorrectly() + { + // Arrange + var jsonConverter = new NewtonsoftJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var complexJson = + """ + { + "Guid": "12345678-1234-1234-1234-123456789012", + "Title": "Test Mapping", + "Description": "A test mapping", + "Priority": 10, + "Scenario": "TestScenario", + "WhenStateIs": "Started", + "SetStateTo": "Finished", + "Request": { + "Path": "/api/test", + "Methods": ["GET", "POST"] + }, + "Response": { + "StatusCode": 201, + "Body": "Test Response" + } + } + """; + + // Act + var result = serializer.DeserializeJsonToArray(complexJson); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(1); + result[0].Guid.Should().Be(Guid.Parse("12345678-1234-1234-1234-123456789012")); + result[0].Title.Should().Be("Test Mapping"); + result[0].Description.Should().Be("A test mapping"); + result[0].Priority.Should().Be(10); + result[0].Scenario.Should().Be("TestScenario"); + result[0].WhenStateIs.Should().Be("Started"); + result[0].SetStateTo.Should().Be("Finished"); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithNewtonsoftJson_NullValue_ShouldThrowException() + { + // Arrange + var jsonConverter = new NewtonsoftJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var nullJson = "null"; + + // Act + Action act = () => serializer.DeserializeJsonToArray(nullJson); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithNewtonsoftJson_PrimitiveValue_ShouldThrowInvalidOperationException() + { + // Arrange + var jsonConverter = new NewtonsoftJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var primitiveJson = "\"string value\""; + + // Act + Action act = () => serializer.DeserializeJsonToArray(primitiveJson); + + // Assert + act.Should().Throw() + .WithMessage("Cannot deserialize the provided value to an array or object."); + } + +#if NET8_0_OR_GREATER + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithSystemTextJson_SingleObject_ShouldReturnArray() + { + // Arrange + var jsonConverter = new SystemTextJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + + // Act + var result = serializer.DeserializeJsonToArray(SingleMappingJson); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(1); + result[0].Guid.Should().Be(Guid.Parse("12345678-1234-1234-1234-123456789012")); + result[0].Priority.Should().Be(1); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithSystemTextJson_Array_ShouldReturnArray() + { + // Arrange + var jsonConverter = new SystemTextJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + + // Act + var result = serializer.DeserializeJsonToArray(ArrayMappingJson); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(2); + result[0].Guid.Should().Be(Guid.Parse("12345678-1234-1234-1234-123456789012")); + result[0].Priority.Should().Be(1); + result[1].Guid.Should().Be(Guid.Parse("87654321-4321-4321-4321-210987654321")); + result[1].Priority.Should().Be(2); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithSystemTextJson_EmptyArray_ShouldReturnEmptyArray() + { + // Arrange + var jsonConverter = new SystemTextJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var emptyArrayJson = "[]"; + + // Act + var result = serializer.DeserializeJsonToArray(emptyArrayJson); + + // Assert + result.Should().NotBeNull(); + result.Should().BeEmpty(); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithSystemTextJson_InvalidJson_ShouldThrowException() + { + // Arrange + var jsonConverter = new SystemTextJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var invalidJson = "not valid json"; + + // Act + Action act = () => serializer.DeserializeJsonToArray(invalidJson); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithSystemTextJson_ComplexMapping_ShouldDeserializeCorrectly() + { + // Arrange + var jsonConverter = new SystemTextJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var complexJson = + """ + { + "Guid": "12345678-1234-1234-1234-123456789012", + "Title": "Test Mapping", + "Description": "A test mapping", + "Priority": 10, + "Scenario": "TestScenario", + "WhenStateIs": "Started", + "SetStateTo": "Finished", + "Request": { + "Path": "/api/test", + "Methods": ["GET", "POST"] + }, + "Response": { + "StatusCode": 201, + "Body": "Test Response" + } + } + """; + + // Act + var result = serializer.DeserializeJsonToArray(complexJson); + + // Assert + result.Should().NotBeNull(); + result.Should().HaveCount(1); + result[0].Guid.Should().Be(Guid.Parse("12345678-1234-1234-1234-123456789012")); + result[0].Title.Should().Be("Test Mapping"); + result[0].Description.Should().Be("A test mapping"); + result[0].Priority.Should().Be(10); + result[0].Scenario.Should().Be("TestScenario"); + result[0].WhenStateIs.Should().Be("Started"); + result[0].SetStateTo.Should().Be("Finished"); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithSystemTextJson_NullValue_ShouldThrowException() + { + // Arrange + var jsonConverter = new SystemTextJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var nullJson = "null"; + + // Act + Action act = () => serializer.DeserializeJsonToArray(nullJson); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void MappingSerializer_DeserializeJsonToArray_WithSystemTextJson_PrimitiveValue_ShouldThrowInvalidOperationException() + { + // Arrange + var jsonConverter = new SystemTextJsonConverter(); + var serializer = new MappingSerializer(jsonConverter); + var primitiveJson = "\"string value\""; + + // Act + Action act = () => serializer.DeserializeJsonToArray(primitiveJson); + + // Assert + act.Should().Throw() + .WithMessage("Cannot deserialize the provided value to an array or object."); + } +#endif +} \ No newline at end of file