using AyCode.Core.Serializers.Binaries; using AyCode.Core.Tests.TestModels; namespace AyCode.Core.Tests.Serialization; /// /// Tests for Source Generator based serialization integration. /// [TestClass] public class GeneratedSerializerIntegrationTests { [TestMethod] public void GeneratedSerializerType_Exists_ForMarkedTypes() { // Arrange - types marked with [AcBinarySerializable] var type = typeof(GeneratedSerializerTestModel); // Act - find the generated serializer type directly var generatedTypeName = $"{type.FullName}_AcBinarySerializer"; var serializerType = type.Assembly.GetType(generatedTypeName); // Assert Assert.IsNotNull(serializerType, $"Generated serializer type '{generatedTypeName}' should exist for [AcBinarySerializable] marked type"); } [TestMethod] public void GeneratedSerializerType_HasCorrectMethods() { // Arrange var type = typeof(SimpleGeneratedModel); // Act - find the generated serializer type directly var generatedTypeName = $"{type.FullName}_AcBinarySerializer"; var serializerType = type.Assembly.GetType(generatedTypeName); // Assert Assert.IsNotNull(serializerType, $"Generated serializer type '{generatedTypeName}' should exist"); var serializeMethod = serializerType.GetMethod("Serialize", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); Assert.IsNotNull(serializeMethod, "Serialize method should exist"); var deserializeMethod = serializerType.GetMethod("Deserialize", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); Assert.IsNotNull(deserializeMethod, "Deserialize method should exist"); var propertyNamesField = serializerType.GetField("PropertyNames", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); Assert.IsNotNull(propertyNamesField, "PropertyNames field should exist"); var propertyNames = propertyNamesField.GetValue(null) as string[]; Assert.IsNotNull(propertyNames, "PropertyNames should not be null"); Assert.AreEqual(3, propertyNames.Length, "SimpleGeneratedModel has 3 properties"); // Verify alphabetical order Assert.AreEqual("Age", propertyNames[0]); Assert.AreEqual("FirstName", propertyNames[1]); Assert.AreEqual("LastName", propertyNames[2]); } [TestMethod] public void GeneratedSerializerPropertyNames_MatchRuntimeOrder() { // This test verifies that the generated property order matches the runtime serializer's order // This is critical for binary compatibility! var type = typeof(GeneratedSerializerTestModel); // Get generated property names var generatedTypeName = $"{type.FullName}_AcBinarySerializer"; var serializerType = type.Assembly.GetType(generatedTypeName); Assert.IsNotNull(serializerType); var propertyNamesField = serializerType.GetField("PropertyNames", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); var generatedNames = propertyNamesField?.GetValue(null) as string[]; Assert.IsNotNull(generatedNames); // Get runtime property names using the same logic as TypeMetadataBase var runtimeProps = type.GetProperties( System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance) .Where(p => p.CanRead && p.CanWrite && !p.GetIndexParameters().Any()) .OrderBy(p => p.Name, StringComparer.Ordinal) .Select(p => p.Name) .ToArray(); // Assert they match CollectionAssert.AreEqual(runtimeProps, generatedNames, "Generated property names must match runtime property order for binary compatibility"); } [TestMethod] public void Serialization_WorksCorrectly_WithGeneratedSerializerPresent() { // This test ensures that regular serialization still works even when // generated serializers are present (they are not yet integrated into the hot path) var original = new GeneratedSerializerTestModel { Id = 42, Name = "Test", IsActive = true, Value = 3.14, Created = new DateTime(2025, 1, 5, 10, 30, 0, DateTimeKind.Utc), UniqueId = Guid.NewGuid(), Price = 99.99m, BigNumber = 9999999999L }; // Serialize and deserialize using the regular path var bytes = AcBinarySerializer.Serialize(original, AcBinarySerializerOptions.WithoutReferenceHandling); var deserialized = AcBinaryDeserializer.Deserialize(bytes); // Assert Assert.IsNotNull(deserialized); Assert.AreEqual(original.Id, deserialized.Id); Assert.AreEqual(original.Name, deserialized.Name); Assert.AreEqual(original.IsActive, deserialized.IsActive); Assert.AreEqual(original.Value, deserialized.Value); Assert.AreEqual(original.Created, deserialized.Created); Assert.AreEqual(original.UniqueId, deserialized.UniqueId); Assert.AreEqual(original.Price, deserialized.Price); Assert.AreEqual(original.BigNumber, deserialized.BigNumber); } [TestMethod] public void NestedType_GeneratedSerializer_IsFound() { // Test that nested types (like QuickBenchmark.TestClassWithRepeatedValues) // have their generated serializers properly named and discoverable var type = typeof(QuickBenchmark.TestClassWithRepeatedValues); var ns = type.Namespace ?? ""; // For nested types, the generated class is at namespace level with just the type name var simpleName = $"{(string.IsNullOrEmpty(ns) ? "" : ns + ".")}{type.Name}_AcBinarySerializer"; var serializerType = type.Assembly.GetType(simpleName); Assert.IsNotNull(serializerType, $"Generated serializer for nested type should be found at '{simpleName}'"); // Verify it has the expected methods Assert.IsNotNull(serializerType.GetMethod("Serialize", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)); Assert.IsNotNull(serializerType.GetMethod("Deserialize", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)); } }