AyCode.Core/AyCode.Core.Tests/TestModels/BenchmarkTestDataProvider.cs

332 lines
11 KiB
C#

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<object>
{
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<TestDataSet> CreateTestDataSets(bool resetId = true)
{
return new List<TestDataSet>
{
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<object>(ReferenceComparer.Instance);
var stack = new Stack<object>();
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; }
/// <summary>
/// Percentage of IId shared references in the data (0-100).
/// Higher values mean more deduplication benefit for Default mode.
/// </summary>
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;
/// <summary>
/// Gets display name including IId ref percentage if set.
/// </summary>
public string DisplayName => IIdRefPercent > 0
? $"{Name} [{IIdRefPercent}% IId refs]"
: Name;
}