AyCode.Core/AyCode.Core.Tests/Serialization/GeneratedSerializerIntegrat...

150 lines
6.6 KiB
C#

using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Tests.TestModels;
namespace AyCode.Core.Tests.Serialization;
/// <summary>
/// Tests for Source Generator based serialization integration.
/// </summary>
[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<GeneratedSerializerTestModel>(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));
}
}