using AyCode.Core.Serializers.Binaries; using System.Collections; using System.Reflection; using System.Runtime.CompilerServices; namespace AyCode.Core.Tests.TestModels; public static class BenchmarkTestDataProvider { private const int FixStrMaxLength = 31; private const string LongStringSuffix = "__Benchmárk_Long_String_Söffix__"; private sealed class ReferenceComparer : IEqualityComparer { public static readonly ReferenceComparer Instance = new(); public new bool Equals(object? x, object? y) => ReferenceEquals(x, y); public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj); } public static List CreateTestDataSets(bool resetId = true) { return new List { CreateSmallTestData(resetId), CreateMediumTestData(resetId), CreateLargeTestData(resetId), CreateRepeatedStringsTestData(resetId), CreateDeepNestedTestData(resetId) }; } public static TestOrder CreateProfilerOrder() { TestDataFactory.ResetIdCounter(); var sharedTag = TestDataFactory.CreateTag("KözösCímke"); var sharedUser = TestDataFactory.CreateUser("közösfelhasználó"); return TestDataFactory.CreateOrder( itemCount: 3, palletsPerItem: 3, measurementsPerPallet: 3, pointsPerMeasurement: 4, sharedTag: sharedTag, sharedUser: sharedUser); } private static TestDataSet CreateSmallTestData(bool resetId = true) { if (resetId) TestDataFactory.ResetIdCounter(); var sharedTag = TestDataFactory.CreateTag("KözösCímke"); var sharedUser = TestDataFactory.CreateUser("közösfelhasználó"); var order = TestDataFactory.CreateOrder( itemCount: 2, palletsPerItem: 2, measurementsPerPallet: 2, pointsPerMeasurement: 2, sharedTag: sharedTag, sharedUser: sharedUser); EnsureAllStringsBypassFixStr(order); ClearDeepLevelRefs(order); return new TestDataSet("Small (2x2x2x2)", order, iidRefPercent: 20); } private static TestDataSet CreateMediumTestData(bool resetId = true) { if (resetId) TestDataFactory.ResetIdCounter(); var sharedTag = TestDataFactory.CreateTag("KözösCímke"); var sharedUser = TestDataFactory.CreateUser("közösfelhasználó"); var sharedMeta = TestDataFactory.CreateMetadata("közös", withChild: true); var sharedPreferences = new UserPreferences { Theme = "sötét", Language = "magyar", NotificationsEnabled = true, EmailDigestFrequency = "hetenkénti" }; sharedUser.Preferences = sharedPreferences; var order = TestDataFactory.CreateOrder( itemCount: 3, palletsPerItem: 3, measurementsPerPallet: 3, pointsPerMeasurement: 4, sharedTag: sharedTag, sharedUser: sharedUser, sharedMetadata: sharedMeta, sharedPreferences: sharedPreferences); EnsureAllStringsBypassFixStr(order); ClearDeepLevelRefs(order); return new TestDataSet("Medium (3x3x3x4)", order, iidRefPercent: 20); } private static TestDataSet CreateLargeTestData(bool resetId = true) { if (resetId) TestDataFactory.ResetIdCounter(); var sharedTag = TestDataFactory.CreateTag("KözösCímke"); var sharedUser = TestDataFactory.CreateUser("közösfelhasználó"); var sharedPreferences = new UserPreferences { Theme = "világos", Language = "német", NotificationsEnabled = false, EmailDigestFrequency = "naponkénti" }; sharedUser.Preferences = sharedPreferences; var order = TestDataFactory.CreateOrder( itemCount: 5, palletsPerItem: 5, measurementsPerPallet: 5, pointsPerMeasurement: 10, sharedTag: sharedTag, sharedUser: sharedUser, sharedPreferences: sharedPreferences); EnsureAllStringsBypassFixStr(order); ClearDeepLevelRefs(order); return new TestDataSet("Large (5x5x5x10)", order, iidRefPercent: 20); } private static TestDataSet CreateRepeatedStringsTestData(bool resetId = true) { if (resetId) TestDataFactory.ResetIdCounter(); var sharedTag = TestDataFactory.CreateTag("IsmétlődőCímke"); var sharedUser = TestDataFactory.CreateUser("ismétlődőfelhasználó"); var sharedPreferences = new UserPreferences { Theme = "sötét", Language = "magyar", NotificationsEnabled = true, EmailDigestFrequency = "hetenkénti" }; sharedUser.Preferences = sharedPreferences; var order = TestDataFactory.CreateOrder( itemCount: 10, palletsPerItem: 2, measurementsPerPallet: 2, pointsPerMeasurement: 2, sharedTag: sharedTag, sharedUser: sharedUser, sharedPreferences: sharedPreferences); // Repeated string fields — ProductName on items + PalletCode on pallets. Both are common // across the hierarchy, exercising string-interning deduplication on the Default preset // (which has UseStringInterning = All). Targeting ~20% repeated-string share overall. // Strings contain non-ASCII characters (Hungarian accented letters → multi-byte UTF-8) so the // benchmark reflects real-world i18n payloads, not just the ASCII FixStr fast-path. foreach (var item in order.Items) { item.Status = TestStatus.Processing; item.ProductName = "TermékNév_IsmétlődőTesztAdat_árvíztűrőtükörfúrógép"; foreach (var pallet in item.Pallets) { pallet.PalletCode = "RaklapKód_IsmétlődőTesztAdat_árvíztűrő"; } } EnsureAllStringsBypassFixStr(order); ClearDeepLevelRefs(order); return new TestDataSet("Repeated Strings (10 items)", order, iidRefPercent: 20); } private static TestDataSet CreateDeepNestedTestData(bool resetId = true) { if (resetId) TestDataFactory.ResetIdCounter(); var sharedTag = TestDataFactory.CreateTag("MélyCímke"); var sharedUser = TestDataFactory.CreateUser("mélyfelhasználó"); var sharedCategory = TestDataFactory.CreateCategory("MélyKategória"); var sharedPreferences = new UserPreferences { Theme = "világos", Language = "francia", NotificationsEnabled = false, EmailDigestFrequency = "havonkénti" }; sharedUser.Preferences = sharedPreferences; var order = TestDataFactory.CreateOrder( itemCount: 2, palletsPerItem: 4, measurementsPerPallet: 4, pointsPerMeasurement: 8, sharedTag: sharedTag, sharedUser: sharedUser, sharedPreferences: sharedPreferences, sharedCategory: sharedCategory); EnsureAllStringsBypassFixStr(order); ClearDeepLevelRefs(order); return new TestDataSet("Deep Nested (2x4x4x8)", order, iidRefPercent: 20); } private static void ClearDeepLevelRefs(TestOrder order) { // Keep shared IId refs at the pallet level (Tag + Inspector) — these contribute the bulk of // the ~20% IId-ref share that the test data targets. Only Category is cleared at this level // (one-of-three clears keep the share moderate). The deeper measurement / point levels are // cleared entirely so deep-tree ref noise does not skew the share upward beyond ~20%. foreach (var item in order.Items) { foreach (var pallet in item.Pallets) { // pallet.Tag = null; // KEEP for ~20% IId-ref share (was cleared) // pallet.Inspector = null; // KEEP for ~20% IId-ref share (was cleared) pallet.Category = null; foreach (var measurement in pallet.Measurements) { measurement.Tag = null; measurement.Operator = null; foreach (var point in measurement.Points) { point.Tag = null; point.Verifier = null; } } } } } private static void EnsureAllStringsBypassFixStr(object? root) { if (root == null) return; var visited = new HashSet(ReferenceComparer.Instance); var stack = new Stack(); stack.Push(root); while (stack.Count > 0) { var current = stack.Pop(); if (!visited.Add(current)) continue; if (current is IEnumerable enumerable && current is not string) { foreach (var item in enumerable) { if (item != null) stack.Push(item); } continue; } var type = current.GetType(); foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { if (!property.CanRead) continue; if (property.PropertyType == typeof(string)) { if (!property.CanWrite) continue; var value = (string?)property.GetValue(current); property.SetValue(current, ToLongString(value)); continue; } if (property.PropertyType.IsValueType || property.PropertyType.IsEnum) continue; var child = property.GetValue(current); if (child != null) stack.Push(child); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static string ToLongString(string? value) { if (string.IsNullOrEmpty(value)) return "Benchmark_String_Value" + LongStringSuffix; if (value.Length > FixStrMaxLength) return value; return value + LongStringSuffix; } } public sealed class TestDataSet { public string Name { get; } public TestOrder Order { get; } /// /// Percentage of IId shared references in the data (0-100). /// Higher values mean more deduplication benefit for Default mode. /// public int IIdRefPercent { get; } public TestDataSet(string name, TestOrder order, int iidRefPercent = 0) { Name = name; Order = order; IIdRefPercent = iidRefPercent; } public string TypeName => Order.GetType().Name; /// /// Gets display name including IId ref percentage if set. /// public string DisplayName => IIdRefPercent > 0 ? $"{Name} [{IIdRefPercent}% IId refs]" : Name; }