561 lines
25 KiB
C#
561 lines
25 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using AyCode.Core.Extensions;
|
|
using AyCode.Core.Serializers;
|
|
using AyCode.Core.Serializers.Binaries;
|
|
using AyCode.Core.Tests.TestModels;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
|
|
namespace AyCode.Core.Tests.Serialization;
|
|
|
|
/// <summary>
|
|
/// Tests for IId-based reference handling in Binary serializer.
|
|
/// Two scenarios:
|
|
/// 1. Same instance referenced multiple times (object identity)
|
|
/// 2. Different instances with same IId.Id (IId-based deduplication)
|
|
///
|
|
/// Tests verify BOTH:
|
|
/// - Serialized output uses ObjectRef (not redundant full objects)
|
|
/// - Deserialized result maintains reference identity
|
|
/// </summary>
|
|
[TestClass]
|
|
public class AcBinarySerializerIIdReferenceTests
|
|
{
|
|
#region Helper Methods
|
|
|
|
/// <summary>
|
|
/// Counts occurrences of ObjectRef in binary data.
|
|
/// Uses BinaryTypeCode.ObjectRef constant to stay in sync with format changes.
|
|
/// </summary>
|
|
private static int CountObjectRefs(byte[] binary, bool writeBinaryToConsole = true)
|
|
{
|
|
if (writeBinaryToConsole) WriteBinaryToConsole(binary);
|
|
|
|
var count = 0;
|
|
for (var i = 0; i < binary.Length; i++)
|
|
{
|
|
if (binary[i] == BinaryTypeCode.ObjectRef)
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
private static void WriteBinaryToConsole(byte[] binary)
|
|
{
|
|
Console.WriteLine();
|
|
Console.WriteLine(BitConverter.ToString(binary));
|
|
Console.WriteLine();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Counts occurrences of a string in binary data (UTF8).
|
|
/// </summary>
|
|
private static int CountStringOccurrences(byte[] binary, string searchString)
|
|
{
|
|
var searchBytes = System.Text.Encoding.UTF8.GetBytes(searchString);
|
|
var count = 0;
|
|
for (var i = 0; i <= binary.Length - searchBytes.Length; i++)
|
|
{
|
|
var match = true;
|
|
for (var j = 0; j < searchBytes.Length; j++)
|
|
{
|
|
if (binary[i + j] != searchBytes[j])
|
|
{
|
|
match = false;
|
|
break;
|
|
}
|
|
}
|
|
if (match) count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Scenario 1: Same Instance (Object Identity)
|
|
|
|
/// <summary>
|
|
/// SCENARIO 1: Same instance referenced multiple times.
|
|
/// Tests all ReferenceHandling modes: None, OnlyId, All
|
|
/// </summary>
|
|
[TestMethod]
|
|
[DataRow(true, true)]
|
|
[DataRow(false, true)]
|
|
[DataRow(true, false)]
|
|
[DataRow(false, false)]
|
|
public void SameInstance_SerializeAndDeserialize(bool useSgen, bool useMeta)
|
|
{
|
|
var modes = new[]
|
|
{
|
|
ReferenceHandlingMode.None,
|
|
ReferenceHandlingMode.OnlyId,
|
|
ReferenceHandlingMode.All
|
|
};
|
|
|
|
foreach (var mode in modes)
|
|
{
|
|
// Arrange: SAME instance used multiple times
|
|
var userPreferences = new UserPreferences();
|
|
var sharedTag = new SharedTag { Id = 1, Name = "ImportantTag", Color = "#FF0000" };
|
|
var sharedUser = new SharedUser { Id = 1, Preferences = userPreferences };
|
|
|
|
var order = new TestOrder_Circ_Ref
|
|
{
|
|
Id = 1,
|
|
OrderNumber = "ORD-001",
|
|
PrimaryTag = sharedTag,
|
|
Owner = sharedUser,
|
|
Items =
|
|
[
|
|
new TestOrderItem_Circ_Ref { Id = 1, ProductName = "Product-A", Tag = sharedTag, Assignee = sharedUser },
|
|
new TestOrderItem_Circ_Ref { Id = 2, ProductName = "Product-B", Tag = sharedTag, Assignee = new SharedUser { Id = 2, Preferences = userPreferences }},
|
|
new TestOrderItem_Circ_Ref { Id = 3, ProductName = "Product-C", Tag = sharedTag, Assignee = new SharedUser { Id = 3, Preferences = userPreferences } }
|
|
]
|
|
};
|
|
|
|
//order.Parent = order.Items[1];
|
|
|
|
if (mode != ReferenceHandlingMode.None) order.Parent = order.Items[1];
|
|
else order.Parent = userPreferences;
|
|
|
|
order.Items[1].ParentOrder = order;
|
|
|
|
var options = new AcBinarySerializerOptions
|
|
{
|
|
ReferenceHandling = mode,
|
|
UseGeneratedCode = useSgen,
|
|
UseMetadata = useMeta,
|
|
MaxDepth = 10
|
|
};
|
|
|
|
Console.WriteLine($"\n========== ReferenceHandling: {options.ReferenceHandling}, UseSgen: {options.UseGeneratedCode}, UseMeta: {options.UseMetadata} ==========");
|
|
|
|
// Act
|
|
var binary = AcBinarySerializer.Serialize(order, options);
|
|
//WriteBinaryToConsole(binary);
|
|
var result = binary.BinaryTo<TestOrder_Circ_Ref>(); // Options from header
|
|
|
|
var objectRefCount = CountObjectRefs(binary, false);
|
|
Console.WriteLine($"Binary size: {binary.Length} bytes");
|
|
Console.WriteLine($"ObjectRef count: {objectRefCount}");
|
|
|
|
Assert.IsNotNull(result, $"[{mode}] Deserialized result is null");
|
|
//Assert.IsNotNull(result.Parent);
|
|
Assert.IsNotNull(result.Owner);
|
|
|
|
// Assert based on mode
|
|
switch (mode)
|
|
{
|
|
case ReferenceHandlingMode.None:
|
|
//none esetén miért nincs infinite loop??? - J.
|
|
// Note: CountObjectRefs raw byte scan is unreliable in None mode —
|
|
// byte 65 (ObjectRef) == ASCII 'A', so "Product-A" and circular-ref
|
|
// depth expansion produce many false positives. Skip count assertion;
|
|
// data integrity checks below verify correct deserialization.
|
|
//WriteBinaryToConsole(binary);
|
|
break;
|
|
|
|
case ReferenceHandlingMode.OnlyId:
|
|
// sharedTag (Id=1) 4x → 3 ObjectRefs, sharedUser (Id=1) 2x → 1 ObjectRef = 4 total
|
|
Assert.IsTrue(objectRefCount >= 4, $"[{mode}] Expected at least 4 ObjectRefs, found {objectRefCount}");
|
|
// IId types should have reference identity
|
|
Assert.AreSame(result.PrimaryTag, result.Items[0].Tag, $"[{mode}] Tag reference identity failed");
|
|
Assert.AreSame(result.Owner, result.Items[0].Assignee, $"[{mode}] User reference identity failed");
|
|
Assert.AreSame(result, result.Items[1].ParentOrder);
|
|
Assert.AreSame(result.Parent, result.Items[1]);
|
|
break;
|
|
|
|
case ReferenceHandlingMode.All:
|
|
// IId types + Non-IId (UserPreferences) should have ObjectRefs
|
|
Assert.IsTrue(objectRefCount >= 4, $"[{mode}] Expected at least 4 ObjectRefs, found {objectRefCount}");
|
|
Assert.AreSame(result.PrimaryTag, result.Items[0].Tag, $"[{mode}] Tag reference identity failed");
|
|
Assert.AreSame(result.Owner, result.Items[0].Assignee, $"[{mode}] User reference identity failed");
|
|
|
|
Assert.AreSame(result, result.Items[1].ParentOrder);
|
|
Assert.AreSame(result.Parent, result.Items[1]);
|
|
|
|
// Non-IId should also have reference identity in All mode
|
|
Assert.AreSame(result.Owner.Preferences, result.Items[0].Assignee.Preferences, $"[{mode}] UserPreferences reference identity failed - Non-IId should work in All mode!");
|
|
break;
|
|
}
|
|
|
|
// Data integrity - always check
|
|
Assert.IsNotNull(result.PrimaryTag, $"[{mode}] PrimaryTag is null");
|
|
Assert.AreEqual(1, result.PrimaryTag.Id, $"[{mode}] PrimaryTag.Id incorrect");
|
|
Assert.AreEqual("ImportantTag", result.PrimaryTag.Name, $"[{mode}] PrimaryTag.Name incorrect");
|
|
Assert.AreEqual(3, result.Items.Count, $"[{mode}] Items count incorrect");
|
|
|
|
Console.WriteLine($"[{mode}] PASSED ✓");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Scenario 2: Different Instances with Same IId (IId-Based Deduplication)
|
|
|
|
/// <summary>
|
|
/// SCENARIO 2: DIFFERENT instances with SAME IId.Id value.
|
|
/// CRITICAL test - if IId-based deduplication works:
|
|
/// - ObjectRef should be used in binary
|
|
/// - Data should be complete after deserialize
|
|
/// - References should be identical (AreSame)
|
|
/// - Different TYPES with same int Id should NOT be confused!
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void DifferentInstances_SameIId_SerializeAndDeserialize()
|
|
{
|
|
// Arrange: DIFFERENT instances but SAME IId.Id
|
|
// CRITICAL: Multiple DIFFERENT TYPES all have Id=1 - must not be confused!
|
|
var sharedTag = new SharedTag { Id = 55, Name = "ImportantTag_55", Color = "#FF0000" };
|
|
var order = new TestOrder
|
|
{
|
|
Id = 1,
|
|
OrderNumber = "ORD-001",
|
|
// All three types have Id=1 - tests (Type, Id) keying, not just Id
|
|
PrimaryTag = new SharedTag { Id = 1, Name = "Tag_Id1", Color = "#FF0000" },
|
|
Owner = new SharedUser { Id = 1, Username = "User_Id1", Email = "user1@test.com" },
|
|
Category = new SharedCategory { Id = 1, Name = "Category_Id1", SortOrder = 10 },
|
|
Items =
|
|
[
|
|
new TestOrderItem
|
|
{
|
|
Id = 1,
|
|
ProductName = "Product-A",
|
|
Tag = new SharedTag { Id = 1, Name = "Tag_Id1", Color = "#FF0000" },
|
|
Assignee = new SharedUser { Id = 1, Username = "User_Id1", Email = "user1@test.com" }
|
|
},
|
|
new TestOrderItem
|
|
{
|
|
Id = 2,
|
|
ProductName = "Product-B",
|
|
Tag = new SharedTag { Id = 1, Name = "Tag_Id1", Color = "#FF0000" },
|
|
Assignee = new SharedUser { Id = 1, Username = "User_Id1", Email = "user1@test.com" }
|
|
},
|
|
new TestOrderItem
|
|
{
|
|
Id = 3,
|
|
ProductName = "Product-C",
|
|
Tag = new SharedTag { Id = 1, Name = "Tag_Id1", Color = "#FF0000" },
|
|
Assignee = new SharedUser { Id = 1, Username = "User_Id1", Email = "user1@test.com" }
|
|
}
|
|
]
|
|
};
|
|
|
|
// Act
|
|
var binary = order.ToBinary();
|
|
var result = binary.BinaryTo<TestOrder>();
|
|
|
|
// Assert 1: Check if ObjectRef is used (IId-based deduplication active)
|
|
var objectRefCount = CountObjectRefs(binary);
|
|
Console.WriteLine($"\nBinary size: {binary.Length} bytes (WithRef)");
|
|
Console.WriteLine($"ObjectRef count: {objectRefCount}");
|
|
|
|
// Assert 3: Reference identity - same TYPE with same Id should be same reference
|
|
// Tags with Id=1 should all be same reference
|
|
Assert.AreSame(result.PrimaryTag, result.Items[0].Tag,
|
|
"CRITICAL: Item[0].Tag should be same reference as PrimaryTag (same SharedTag.Id=1)");
|
|
Assert.AreSame(result.PrimaryTag, result.Items[1].Tag,
|
|
"CRITICAL: Item[1].Tag should be same reference as PrimaryTag (same SharedTag.Id=1)");
|
|
Assert.AreSame(result.PrimaryTag, result.Items[2].Tag,
|
|
"CRITICAL: Item[2].Tag should be same reference as PrimaryTag (same SharedTag.Id=1)");
|
|
|
|
// Users with Id=1 should all be same reference
|
|
Assert.AreSame(result.Owner, result.Items[0].Assignee,
|
|
"CRITICAL: Item[0].Assignee should be same reference as Owner (same SharedUser.Id=1)");
|
|
Assert.AreSame(result.Owner, result.Items[1].Assignee,
|
|
"CRITICAL: Item[1].Assignee should be same reference as Owner (same SharedUser.Id=1)");
|
|
Assert.AreSame(result.Owner, result.Items[2].Assignee,
|
|
"CRITICAL: Item[2].Assignee should be same reference as Owner (same SharedUser.Id=1)");
|
|
|
|
// Assert 4: Different TYPES with same Id should NOT be same reference!
|
|
Assert.AreNotSame<object>(result.PrimaryTag, result.Owner,
|
|
"CRITICAL BUG: Tag and User are same reference! Types with same int Id were confused!");
|
|
Assert.AreNotSame<object>(result.PrimaryTag, result.Category,
|
|
"CRITICAL BUG: Tag and Category are same reference! Types with same int Id were confused!");
|
|
Assert.AreNotSame<object>(result.Owner, result.Category,
|
|
"CRITICAL BUG: User and Category are same reference! Types with same int Id were confused!");
|
|
// 4 Tags, 4 Users - each should have 3 ObjectRefs = 6 total minimum
|
|
Assert.IsTrue(objectRefCount >= 6,
|
|
$"CRITICAL: Expected at least 6 ObjectRef entries (3 per type for Tag and User), found {objectRefCount}. " +
|
|
"IId-based reference deduplication is NOT working!");
|
|
|
|
// Assert 2: Data integrity - ALL data present and correct
|
|
Assert.IsNotNull(result, "Deserialized result is null");
|
|
|
|
// Tag data
|
|
Assert.IsNotNull(result.PrimaryTag, "PrimaryTag is null - data lost!");
|
|
Assert.AreEqual(1, result.PrimaryTag.Id, "PrimaryTag.Id incorrect");
|
|
Assert.AreEqual("Tag_Id1", result.PrimaryTag.Name, "PrimaryTag.Name incorrect - might be confused with User!");
|
|
Assert.AreEqual("#FF0000", result.PrimaryTag.Color, "PrimaryTag.Color incorrect");
|
|
|
|
// User data - MUST NOT be confused with Tag (both have Id=1)
|
|
Assert.IsNotNull(result.Owner, "Owner is null - data lost!");
|
|
Assert.AreEqual(1, result.Owner.Id, "Owner.Id incorrect");
|
|
Assert.AreEqual("User_Id1", result.Owner.Username, "Owner.Username incorrect - might be confused with Tag!");
|
|
Assert.AreEqual("user1@test.com", result.Owner.Email, "Owner.Email incorrect");
|
|
|
|
// Category data - MUST NOT be confused with Tag or User (all have Id=1)
|
|
Assert.IsNotNull(result.Category, "Category is null - data lost!");
|
|
Assert.AreEqual(1, result.Category.Id, "Category.Id incorrect");
|
|
Assert.AreEqual("Category_Id1", result.Category.Name, "Category.Name incorrect - might be confused with Tag!");
|
|
Assert.AreEqual(10, result.Category.SortOrder, "Category.SortOrder incorrect");
|
|
|
|
Assert.IsNotNull(result.Items, "Items is null");
|
|
Assert.AreEqual(3, result.Items.Count, "Items count incorrect");
|
|
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
// Tag in items
|
|
Assert.IsNotNull(result.Items[i].Tag, $"Items[{i}].Tag is null - data lost!");
|
|
Assert.AreEqual(1, result.Items[i].Tag!.Id, $"Items[{i}].Tag.Id incorrect");
|
|
Assert.AreEqual("Tag_Id1", result.Items[i].Tag.Name, $"Items[{i}].Tag.Name incorrect - confused with User?");
|
|
|
|
// User in items - MUST NOT be confused with Tag
|
|
Assert.IsNotNull(result.Items[i].Assignee, $"Items[{i}].Assignee is null - data lost!");
|
|
Assert.AreEqual(1, result.Items[i].Assignee!.Id, $"Items[{i}].Assignee.Id incorrect");
|
|
Assert.AreEqual("User_Id1", result.Items[i].Assignee.Username, $"Items[{i}].Assignee.Username incorrect - confused with Tag?");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Size comparison: Same IId should result in smaller binary + verify data integrity.
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void DifferentInstances_SameIId_SmallerBinaryWithDataIntegrity()
|
|
{
|
|
// Arrange: 10 different instances with SAME IId
|
|
var orderWithSameIId = new TestOrder
|
|
{
|
|
Id = 1,
|
|
OrderNumber = "SAME-IID",
|
|
Items = Enumerable.Range(1, 10).Select(i => new TestOrderItem
|
|
{
|
|
Id = i,
|
|
ProductName = $"Product-{i}",
|
|
// All have SAME IId.Id = 1, but DIFFERENT instances
|
|
Assignee = new SharedUser { Id = 1, Username = "shared_user_name", Email = "shared@test.com" }
|
|
}).ToList()
|
|
};
|
|
|
|
// Arrange: 10 different instances with DIFFERENT IIds
|
|
var orderWithDifferentIIds = new TestOrder
|
|
{
|
|
Id = 1,
|
|
OrderNumber = "DIFF-IID",
|
|
Items = Enumerable.Range(1, 10).Select(i => new TestOrderItem
|
|
{
|
|
Id = i,
|
|
ProductName = $"Product-{i}",
|
|
// All have DIFFERENT IId.Id
|
|
Assignee = new SharedUser { Id = i * 100, Username = "unique_user_name", Email = "unique@test.com" }
|
|
}).ToList()
|
|
};
|
|
|
|
// Act
|
|
var sameIIdBinary = orderWithSameIId.ToBinary();
|
|
var diffIIdBinary = orderWithDifferentIIds.ToBinary();
|
|
var sameIIdResult = sameIIdBinary.BinaryTo<TestOrder>();
|
|
var diffIIdResult = diffIIdBinary.BinaryTo<TestOrder>();
|
|
|
|
// Assert 1: Size comparison
|
|
Console.WriteLine($"Same IId binary size: {sameIIdBinary.Length} bytes");
|
|
Console.WriteLine($"Different IId binary size: {diffIIdBinary.Length} bytes");
|
|
Console.WriteLine($"Size difference: {diffIIdBinary.Length - sameIIdBinary.Length} bytes");
|
|
|
|
Assert.IsTrue(sameIIdBinary.Length < diffIIdBinary.Length,
|
|
$"Same IId ({sameIIdBinary.Length}b) should be smaller than different IIds ({diffIIdBinary.Length}b). " +
|
|
"IId-based deduplication NOT working!");
|
|
|
|
// Assert 2: Data integrity for sameIId result
|
|
Assert.IsNotNull(sameIIdResult, "sameIIdResult is null");
|
|
Assert.IsNotNull(sameIIdResult.Items, "sameIIdResult.Items is null");
|
|
Assert.AreEqual(10, sameIIdResult.Items.Count, "sameIIdResult should have 10 items");
|
|
|
|
for (var i = 0; i < 10; i++)
|
|
{
|
|
Assert.IsNotNull(sameIIdResult.Items[i].Assignee,
|
|
$"sameIIdResult.Items[{i}].Assignee is null - data lost!");
|
|
Assert.AreEqual(1, sameIIdResult.Items[i].Assignee!.Id,
|
|
$"sameIIdResult.Items[{i}].Assignee.Id should be 1");
|
|
Assert.AreEqual("shared_user_name", sameIIdResult.Items[i].Assignee.Username,
|
|
$"sameIIdResult.Items[{i}].Assignee.Username incorrect");
|
|
}
|
|
|
|
// Assert 3: Reference identity for sameIId
|
|
var firstAssignee = sameIIdResult.Items[0].Assignee;
|
|
for (var i = 1; i < 10; i++)
|
|
{
|
|
Assert.AreSame(firstAssignee, sameIIdResult.Items[i].Assignee,
|
|
$"CRITICAL: Items[{i}].Assignee should be same reference as Items[0].Assignee (same IId.Id=1)");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Guid-Based IId Tests
|
|
|
|
/// <summary>
|
|
/// Guid IId with same instance - validates ObjectRef + data integrity + reference identity.
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GuidIId_SameInstance_SerializeAndDeserialize()
|
|
{
|
|
// Arrange: SAME instance
|
|
var sharedGuid = Guid.NewGuid();
|
|
var sharedItem = new TestGuidItem { Id = sharedGuid, Name = "SharedGuidItem" };
|
|
|
|
var order = new TestGuidOrder
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Code = "GUID-001",
|
|
Count = 3,
|
|
Items = [sharedItem, sharedItem, sharedItem]
|
|
};
|
|
|
|
// Act
|
|
var binary = order.ToBinary();
|
|
var result = binary.BinaryTo<TestGuidOrder>();
|
|
|
|
// Assert 1: ObjectRef should be present
|
|
var objectRefCount = CountObjectRefs(binary);
|
|
Console.WriteLine($"Binary size: {binary.Length} bytes");
|
|
Console.WriteLine($"ObjectRef count: {objectRefCount}");
|
|
|
|
Assert.IsTrue(objectRefCount >= 2, $"Expected at least 2 ObjectRefs, found {objectRefCount}");
|
|
|
|
// Assert 2: Data integrity - all items present and correct
|
|
Assert.IsNotNull(result, "Result is null");
|
|
Assert.IsNotNull(result.Items, "Items is null");
|
|
Assert.AreEqual(3, result.Items.Count, "Items count incorrect");
|
|
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
Assert.IsNotNull(result.Items[i], $"Items[{i}] is null");
|
|
Assert.AreEqual(sharedGuid, result.Items[i].Id, $"Items[{i}].Id incorrect");
|
|
Assert.AreEqual("SharedGuidItem", result.Items[i].Name, $"Items[{i}].Name incorrect");
|
|
}
|
|
|
|
// Assert 3: Reference identity
|
|
Assert.AreSame(result.Items[0], result.Items[1], "Items[0] and Items[1] should be same reference");
|
|
Assert.AreSame(result.Items[1], result.Items[2], "Items[1] and Items[2] should be same reference");
|
|
}
|
|
|
|
/// <summary>
|
|
/// CRITICAL: Guid IId with different instances but same Id - tests IId-based deduplication.
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void GuidIId_DifferentInstances_SameId_SerializeAndDeserialize()
|
|
{
|
|
// Arrange: DIFFERENT instances but SAME Guid
|
|
var sharedGuid = Guid.NewGuid();
|
|
|
|
var order = new TestGuidOrder
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Code = "GUID-001",
|
|
Count = 3,
|
|
Items =
|
|
[
|
|
new TestGuidItem { Id = sharedGuid, Name = "SharedGuidItem" },
|
|
new TestGuidItem { Id = sharedGuid, Name = "SharedGuidItem" },
|
|
new TestGuidItem { Id = sharedGuid, Name = "SharedGuidItem" }
|
|
]
|
|
};
|
|
|
|
// Act
|
|
var binary = order.ToBinary();
|
|
var result = binary.BinaryTo<TestGuidOrder>();
|
|
|
|
// Assert 1: ObjectRef should be present if IId-based dedup works
|
|
var objectRefCount = CountObjectRefs(binary);
|
|
Console.WriteLine($"Binary size: {binary.Length} bytes");
|
|
Console.WriteLine($"ObjectRef count: {objectRefCount}");
|
|
|
|
Assert.IsTrue(objectRefCount >= 2,
|
|
$"CRITICAL: Expected at least 2 ObjectRefs for same Guid IId, found {objectRefCount}. " +
|
|
"Guid-based IId deduplication NOT working!");
|
|
|
|
// Assert 2: Data integrity - all items present and correct
|
|
Assert.IsNotNull(result, "Result is null");
|
|
Assert.IsNotNull(result.Items, "Items is null");
|
|
Assert.AreEqual(3, result.Items.Count, "Items count incorrect");
|
|
|
|
for (var i = 0; i < 3; i++)
|
|
{
|
|
Assert.IsNotNull(result.Items[i], $"Items[{i}] is null - data lost!");
|
|
Assert.AreEqual(sharedGuid, result.Items[i].Id, $"Items[{i}].Id incorrect");
|
|
Assert.AreEqual("SharedGuidItem", result.Items[i].Name, $"Items[{i}].Name incorrect");
|
|
}
|
|
|
|
// Assert 3: Reference identity - if IId-based, should be same reference
|
|
Assert.AreSame(result.Items[0], result.Items[1],
|
|
"CRITICAL: Items[0] and Items[1] should be same reference (same Guid)");
|
|
Assert.AreSame(result.Items[1], result.Items[2],
|
|
"CRITICAL: Items[1] and Items[2] should be same reference (same Guid)");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Data Integrity Tests
|
|
|
|
/// <summary>
|
|
/// Diagnostic test to verify IId detection works correctly.
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void IIdDetection_Diagnostic()
|
|
{
|
|
// Test GetIdInfo directly
|
|
var sharedTagType = typeof(SharedTag);
|
|
var idInfo = AyCode.Core.Helpers.JsonUtilities.GetIdInfo(sharedTagType);
|
|
|
|
Console.WriteLine($"SharedTag GetIdInfo: IsId={idInfo.IsId}, IdType={idInfo.IdType?.Name}");
|
|
Assert.IsTrue(idInfo.IsId, "SharedTag should be detected as IId<int>");
|
|
Assert.AreEqual(typeof(int), idInfo.IdType, "SharedTag Id type should be int");
|
|
|
|
// Test SharedUser
|
|
var sharedUserType = typeof(SharedUser);
|
|
var userIdInfo = AyCode.Core.Helpers.JsonUtilities.GetIdInfo(sharedUserType);
|
|
Console.WriteLine($"SharedUser GetIdInfo: IsId={userIdInfo.IsId}, IdType={userIdInfo.IdType?.Name}");
|
|
Assert.IsTrue(userIdInfo.IsId, "SharedUser should be detected as IId<int>");
|
|
|
|
// Test TestGuidItem
|
|
var guidItemType = typeof(TestGuidItem);
|
|
var guidIdInfo = AyCode.Core.Helpers.JsonUtilities.GetIdInfo(guidItemType);
|
|
Console.WriteLine($"TestGuidItem GetIdInfo: IsId={guidIdInfo.IsId}, IdType={guidIdInfo.IdType?.Name}");
|
|
Assert.IsTrue(guidIdInfo.IsId, "TestGuidItem should be detected as IId<Guid>");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verify data is correct regardless of reference handling.
|
|
/// </summary>
|
|
[TestMethod]
|
|
public void SharedCategory_DataIntegrity()
|
|
{
|
|
var categories = new List<SharedCategory>
|
|
{
|
|
new() { Id = 1, Name = "Category1", SortOrder = 1, IsDefault = true },
|
|
new() { Id = 2, Name = "Category2", SortOrder = 2, ParentCategoryId = 1 },
|
|
new() { Id = 3, Name = "Category3", SortOrder = 3, ParentCategoryId = 1 }
|
|
};
|
|
|
|
var binary = categories.ToBinary();
|
|
var result = binary.BinaryTo<List<SharedCategory>>();
|
|
|
|
Assert.IsNotNull(result);
|
|
Assert.AreEqual(3, result.Count);
|
|
|
|
Assert.AreEqual(1, result[0].Id);
|
|
Assert.AreEqual("Category1", result[0].Name);
|
|
Assert.IsTrue(result[0].IsDefault);
|
|
|
|
Assert.AreEqual(2, result[1].Id);
|
|
Assert.AreEqual(1, result[1].ParentCategoryId);
|
|
|
|
Assert.AreEqual(3, result[2].Id);
|
|
Assert.AreEqual(1, result[2].ParentCategoryId);
|
|
}
|
|
|
|
#endregion
|
|
}
|