using FluentAssertions; using LCU.API.Internal.DocumentLib.Containers; using LCU.Library.Internal.DocumentModels.Converter; using LCU.Library.Internal.DocumentModels.Responses; using Newtonsoft.Json; using JsonSerializer = System.Text.Json.JsonSerializer; namespace LCU.Library.Internal.DocumentModelsTest.Converter; public class PolymorphicJsonConverterTest { public class SystemPolymorphicJsonConverterTest { [Test] public void WriteThenRead_AbstractBaseClassImplementation_DeserializesAsImplementation() { AbstractBaseClass original = new ConcreteClass(); var serialized = JsonSerializer.Serialize(original); var deserialized = JsonSerializer.Deserialize(serialized); Assert.IsInstanceOf(deserialized); deserialized.Should().BeEquivalentTo(original); } [Test] public void Write_TypeDoesNotSpecifyKnownSubclasses_ThrowsException() { DoesNotSpecifyKnownTypes original = new UnknownSubtype(); Assert.Throws(() => JsonSerializer.Serialize(original)); } } public class NewtonsoftPolymorphicJsonConverterTest { [Test] public void WriteThenRead_AbstractBaseClassImplementation_DeserializesAsImplementation() { AbstractBaseClass original = new ConcreteClass(); var serialized = JsonConvert.SerializeObject(original); var deserialized = JsonConvert.DeserializeObject(serialized); Assert.IsInstanceOf(deserialized); deserialized.Should().BeEquivalentTo(original); } [Test] public void Write_TypeDoesNotSpecifyKnownSubclasses_ThrowsException() { DoesNotSpecifyKnownTypes original = new UnknownSubtype(); Assert.Throws(() => JsonConvert.SerializeObject(original)); } } public class NewtonsoftToSystemPolymorphicJsonConverterTest { [Test] public void WriteThenRead_AbstractBaseClassImplementation_DeserializesAsImplementation() { AbstractBaseClass original = new ConcreteClass(); var serialized = JsonConvert.SerializeObject(original); var deserialized = JsonSerializer.Deserialize(serialized); Assert.IsInstanceOf(deserialized); deserialized.Should().BeEquivalentTo(original); } } public class SystemToNewtonsoftPolymorphicJsonConverterTest { [Test] public void WriteThenRead_AbstractBaseClassImplementation_DeserializesAsImplementation() { AbstractBaseClass original = new ConcreteClass(); var serialized = JsonSerializer.Serialize(original); var deserialized = JsonConvert.DeserializeObject(serialized); Assert.IsInstanceOf(deserialized); deserialized.Should().BeEquivalentTo(original); } [Test] [Category("Integration")] public void WriteThenRead_DocumentFieldAuditWithValues_DeserializesCurrentAndPrevious() { DocumentAuditResponse original = new DocumentFieldAuditResponse { DocumentId = Guid.NewGuid(), Source = Guid.NewGuid().ToString(), Date = DateTime.Now, UserId = Guid.NewGuid().ToString(), Field = nameof(DocumentInformation.Attributes), CurrentValue = new { PersonNumber = Guid.NewGuid().ToString(), AccountNumber = Guid.NewGuid().ToString() }, PreviousValue = new { PersonNumber = Guid.NewGuid().ToString(), AccountNumber = Guid.NewGuid().ToString() } }; var deserialized = JsonConvert.DeserializeObject(JsonSerializer.Serialize(original)); for (var i = 0; i <= 5; i++) { deserialized = JsonConvert.DeserializeObject(JsonSerializer.Serialize(deserialized)); } var originalFieldAudit = original as DocumentFieldAuditResponse; var deserializedFieldAudit = deserialized as DocumentFieldAuditResponse; //caution: fluent assertions object comparison does not compare expando objects correctly as of v6.7.0 //it will report the below four properties as missing, despite them having made it through two serializations Assert.AreEqual(originalFieldAudit.CurrentValue.PersonNumber, deserializedFieldAudit.CurrentValue.PersonNumber); Assert.AreEqual(originalFieldAudit.CurrentValue.AccountNumber, deserializedFieldAudit.CurrentValue.AccountNumber); Assert.AreEqual(originalFieldAudit.PreviousValue.PersonNumber, deserializedFieldAudit.PreviousValue.PersonNumber); Assert.AreEqual(originalFieldAudit.PreviousValue.AccountNumber, deserializedFieldAudit.PreviousValue.AccountNumber); } [Test] [Category("Integration")] public void WriteThenRead_DocumentFieldAuditWithNullValues_DeserializesCurrentAndPrevious() { DocumentAuditResponse original = new DocumentFieldAuditResponse { DocumentId = Guid.NewGuid(), Source = Guid.NewGuid().ToString(), Date = DateTime.Now, UserId = Guid.NewGuid().ToString(), Field = nameof(DocumentInformation.Attributes), CurrentValue = null, PreviousValue = null }; var deserialized = JsonConvert.DeserializeObject(JsonSerializer.Serialize(original)); for (var i = 0; i <= 5; i++) { deserialized = JsonConvert.DeserializeObject(JsonSerializer.Serialize(deserialized)); } var originalFieldAudit = original as DocumentFieldAuditResponse; var deserializedFieldAudit = deserialized as DocumentFieldAuditResponse; //caution: fluent assertions object comparison does not compare expando objects correctly as of v6.7.0 //it will report the below four properties as missing, despite them having made it through two serializations Assert.AreEqual(originalFieldAudit.CurrentValue, deserializedFieldAudit.CurrentValue); Assert.AreEqual(originalFieldAudit.PreviousValue, deserializedFieldAudit.PreviousValue); } [Test] [Category("Integration")] public void WriteThenRead_DocumentFieldAuditWithBooleanValues_DeserializesCurrentAndPrevious() { DocumentAuditResponse original = new DocumentFieldAuditResponse { DocumentId = Guid.NewGuid(), Source = Guid.NewGuid().ToString(), Date = DateTime.Now, UserId = Guid.NewGuid().ToString(), Field = nameof(DocumentInformation.Attributes), CurrentValue = true, PreviousValue = false }; var deserialized = JsonConvert.DeserializeObject(JsonSerializer.Serialize(original)); for (var i = 0; i <= 5; i++) { deserialized = JsonConvert.DeserializeObject(JsonSerializer.Serialize(deserialized)); } var originalFieldAudit = original as DocumentFieldAuditResponse; var deserializedFieldAudit = deserialized as DocumentFieldAuditResponse; //caution: fluent assertions object comparison does not compare expando objects correctly as of v6.7.0 //it will report the below four properties as missing, despite them having made it through two serializations Assert.AreEqual(originalFieldAudit.CurrentValue, deserializedFieldAudit.CurrentValue); Assert.AreEqual(originalFieldAudit.PreviousValue, deserializedFieldAudit.PreviousValue); } } [System.Text.Json.Serialization.JsonConverter(typeof(SystemPolymorphicJsonConverter))] [Newtonsoft.Json.JsonConverter(typeof(NewtonsoftPolymorphicJsonConverter))] [JsonKnownTypes(typeof(ConcreteClass))] private abstract class AbstractBaseClass { public Guid AbstractId { get; init; } = Guid.NewGuid(); public NestedType Nested { get; init; } = new(); } private class ConcreteClass : AbstractBaseClass { public Guid ConcreteId { get; init; } = Guid.NewGuid(); } private class NestedType { public Guid NestedId { get; init; } = Guid.NewGuid(); } [System.Text.Json.Serialization.JsonConverter(typeof(SystemPolymorphicJsonConverter))] [Newtonsoft.Json.JsonConverter(typeof(NewtonsoftPolymorphicJsonConverter))] private abstract class DoesNotSpecifyKnownTypes { } private class UnknownSubtype : DoesNotSpecifyKnownTypes { } }