using AyCode.Core.Extensions; using AyCode.Core.Serializers.Binaries; using FruitBank.Common.Entities; using System.Reflection; namespace FruitBankHybrid.Shared.Tests; [TestClass] public class StockTakingSerializerTests { [TestMethod] public void StockTaking_WithNullItems_RoundTrip() { var stockTaking = new StockTaking { Id = 1, StartDateTime = new DateTime(2025, 1, 24, 10, 0, 0, DateTimeKind.Utc), IsClosed = false, Creator = 6, Created = new DateTime(2025, 1, 24, 15, 25, 0, DateTimeKind.Utc), Modified = new DateTime(2025, 1, 24, 16, 0, 0, DateTimeKind.Utc), StockTakingItems = null }; // Log StockTaking properties Console.WriteLine("=== StockTaking Properties ==="); var stProps = typeof(StockTaking).GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanRead && p.GetIndexParameters().Length == 0) .ToArray(); for (int i = 0; i < stProps.Length; i++) Console.WriteLine($" [{i}] {stProps[i].Name} : {stProps[i].PropertyType.Name} (from: {stProps[i].DeclaringType?.Name})"); // Log StockTakingItem properties Console.WriteLine("\n=== StockTakingItem Properties ==="); var stiProps = typeof(StockTakingItem).GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanRead && p.GetIndexParameters().Length == 0) .ToArray(); for (int i = 0; i < stiProps.Length; i++) { var hasIgnore = Attribute.IsDefined(stiProps[i], typeof(Newtonsoft.Json.JsonIgnoreAttribute)) || Attribute.IsDefined(stiProps[i], typeof(System.Text.Json.Serialization.JsonIgnoreAttribute)); Console.WriteLine($" [{i}] {stiProps[i].Name} : {stiProps[i].PropertyType.Name}{(hasIgnore ? " [IGNORED]" : "")}"); } var binary = stockTaking.ToBinary(); Console.WriteLine($"\nBinary length: {binary.Length}"); // Parse header var pos = 0; var version = binary[pos++]; var marker = binary[pos++]; Console.WriteLine($"Version: {version}, Marker: 0x{marker:X2}"); if ((marker & 0x10) != 0) { var propCount = binary[pos++]; Console.WriteLine($"\n=== HEADER ({propCount} properties) ==="); for (int i = 0; i < propCount; i++) { var strLen = binary[pos++]; var propName = System.Text.Encoding.UTF8.GetString(binary, pos, strLen); pos += strLen; Console.WriteLine($" [{i}]: '{propName}'"); } } // Deserialize try { var result = binary.BinaryTo(); Console.WriteLine($"\n=== RESULT ==="); Console.WriteLine($"Id: {result?.Id}"); Console.WriteLine($"Creator: {result?.Creator}"); Console.WriteLine($"Created: {result?.Created}"); Assert.IsNotNull(result); Assert.AreEqual(1, result.Id, "Id mismatch"); Assert.AreEqual(6, result.Creator, $"Creator should be 6, got {result.Creator}"); Assert.AreEqual(stockTaking.Created, result.Created, $"Created mismatch"); } catch (Exception ex) { Console.WriteLine($"\n=== ERROR ==="); Console.WriteLine(ex.Message); throw; } } [TestMethod] public void ListOfStockTaking_WithNullItems_RoundTrip() { var stockTakings = new List { new() { Id = 1, StartDateTime = DateTime.UtcNow, IsClosed = false, Creator = 6, Created = DateTime.UtcNow, Modified = DateTime.UtcNow, StockTakingItems = null }, new() { Id = 2, StartDateTime = DateTime.UtcNow, IsClosed = true, Creator = 12, Created = DateTime.UtcNow, Modified = DateTime.UtcNow, StockTakingItems = null } }; var binary = stockTakings.ToBinary(); Console.WriteLine($"Binary length: {binary.Length}"); var result = binary.BinaryTo>(); Assert.IsNotNull(result); Assert.AreEqual(2, result.Count); Assert.AreEqual(6, result[0].Creator, $"First Creator should be 6, got {result[0].Creator}"); Assert.AreEqual(12, result[1].Creator, $"Second Creator should be 12, got {result[1].Creator}"); } [TestMethod] public void StockTaking_DebugBodyProperties() { var stockTaking = new StockTaking { Id = 1, StartDateTime = new DateTime(2025, 1, 24, 10, 0, 0, DateTimeKind.Utc), IsClosed = false, Creator = 6, Created = new DateTime(2025, 1, 24, 15, 25, 0, DateTimeKind.Utc), Modified = new DateTime(2025, 1, 24, 16, 0, 0, DateTimeKind.Utc), StockTakingItems = null }; var binary = stockTaking.ToBinary(); // Parse header var pos = 0; var version = binary[pos++]; var marker = binary[pos++]; var propertyNames = new List(); if ((marker & 0x10) != 0) { var propCount = (int)binary[pos++]; // Simplified VarUInt read for (int i = 0; i < propCount; i++) { var strLen = (int)binary[pos++]; var propName = System.Text.Encoding.UTF8.GetString(binary, pos, strLen); pos += strLen; propertyNames.Add(propName); } } // Parse body Console.WriteLine($"\n=== BODY (starts at position {pos}) ==="); var objectMarker = binary[pos++]; Console.WriteLine($"Object marker: 0x{objectMarker:X2}"); // Read ref ID (VarInt) var refIdByte = binary[pos]; if ((refIdByte & 0x80) == 0) pos++; else pos += 2; // Read property count var bodyPropCount = binary[pos++]; Console.WriteLine($"Body property count: {bodyPropCount}"); for (int i = 0; i < bodyPropCount; i++) { var propIndex = binary[pos++]; var propName = propIndex < propertyNames.Count ? propertyNames[propIndex] : $"UNKNOWN({propIndex})"; var valueType = binary[pos]; string valueInfo; if (valueType == 0x14) // DateTime { valueInfo = "DateTime"; pos += 10; } else if (valueType >= 0xD0) // TinyInt { var tinyValue = valueType - 0xD0; valueInfo = $"TinyInt({tinyValue})"; pos += 1; } else if (valueType == 0x03) { valueInfo = "False"; pos += 1; } else if (valueType == 0x02) { valueInfo = "True"; pos += 1; } else { valueInfo = $"0x{valueType:X2}"; break; } Console.WriteLine($" Body[{i}]: index={propIndex} -> '{propName}' = {valueInfo}"); } } [TestMethod] public void StockTaking_ExactProductionData_RoundTrip() { var stockTakings = new List { new() { Id = 7, StartDateTime = new DateTime(2025, 12, 3, 8, 55, 43, 539, DateTimeKind.Utc), IsClosed = false, Creator = 6, Created = new DateTime(2025, 12, 3, 7, 55, 43, 571, DateTimeKind.Utc), Modified = new DateTime(2025, 12, 3, 7, 55, 43, 571, DateTimeKind.Utc), StockTakingItems = null }, new() { Id = 6, StartDateTime = new DateTime(2025, 12, 2, 8, 21, 26, 439, DateTimeKind.Utc), IsClosed = true, Creator = 6, Created = new DateTime(2025, 12, 2, 7, 21, 26, 468, DateTimeKind.Utc), Modified = new DateTime(2025, 12, 2, 7, 21, 26, 468, DateTimeKind.Utc), StockTakingItems = null }, new() { Id = 3, StartDateTime = new DateTime(2025, 11, 30, 14, 1, 55, 663, DateTimeKind.Utc), IsClosed = true, Creator = 6, Created = new DateTime(2025, 11, 30, 13, 1, 55, 692, DateTimeKind.Utc), Modified = new DateTime(2025, 11, 30, 13, 1, 55, 692, DateTimeKind.Utc), StockTakingItems = null }, new() { Id = 2, StartDateTime = new DateTime(2025, 11, 30, 8, 20, 2, 182, DateTimeKind.Utc), IsClosed = true, Creator = 6, Created = new DateTime(2025, 11, 30, 7, 20, 3, 331, DateTimeKind.Utc), Modified = new DateTime(2025, 11, 30, 7, 20, 3, 331, DateTimeKind.Utc), StockTakingItems = null }, new() { Id = 1, StartDateTime = new DateTime(2025, 11, 30, 8, 18, 59, 693, DateTimeKind.Utc), IsClosed = true, Creator = 6, Created = new DateTime(2025, 11, 30, 7, 19, 1, 849, DateTimeKind.Utc), Modified = new DateTime(2025, 11, 30, 7, 19, 1, 877, DateTimeKind.Utc), StockTakingItems = null } }; var binary = stockTakings.ToBinary(); Console.WriteLine($"Binary length: {binary.Length}"); var result = binary.BinaryTo>(); Assert.IsNotNull(result); Assert.AreEqual(5, result.Count); foreach (var item in result) { Assert.AreEqual(6, item.Creator, $"StockTaking Id={item.Id}: Creator should be 6, got {item.Creator}"); } } }