AyCode.Core/AyCode.Benchmark/Workloads/Scenarios/RoundTripValidator.cs

50 lines
2.1 KiB
C#

using System.Text.Json;
namespace AyCode.Core.Benchmarks.Workloads.Scenarios;
/// <summary>
/// Round-trip correctness validator — serializes both sides to canonical System.Text.Json form
/// and compares the resulting strings. Works for any object graph without a custom comparer (slower
/// than property-by-property but universal). Used by every benchmark's <c>VerifyRoundTrip()</c>
/// implementation as the deep-equality oracle before warmup begins.
/// </summary>
public static class RoundTripValidator
{
#if !AYCODE_NATIVEAOT
private static readonly JsonSerializerOptions VerifyJsonOpts = new()
{
WriteIndented = false,
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles
};
#endif
/// <summary>
/// Round-trip equality check via canonical System.Text.Json. Returns true if both sides serialize
/// to identical JSON strings.
/// </summary>
/// <remarks>
/// AOT publish skip: <c>System.Text.Json</c>'s reflection path uses runtime closed-generic instantiation
/// (<c>JsonPropertyInfo&lt;TestStatus&gt;</c> et al.) that the trimmer drops, causing
/// <c>NotSupportedException: missing native code or metadata</c>. The validation is JIT-only — the actual
/// benchmark Serialize/Deserialize loops don't touch this path. Under AOT we return <c>true</c> so all
/// <c>VerifyRoundTrip()</c> calls pass without running the cross-format validation.
/// </remarks>
public static bool DeepEqualsViaJson(object? a, object? b)
{
#if AYCODE_NATIVEAOT
// Skip cross-format validation under AOT — STJ reflection path is incompatible. The roundtrip
// itself still runs (caller-side Serialize+Deserialize), just the JSON-canonical compare is bypassed.
return true;
#else
if (a == null && b == null) return true;
if (a == null || b == null) return false;
var jsonA = JsonSerializer.Serialize(a, VerifyJsonOpts);
var jsonB = JsonSerializer.Serialize(b, VerifyJsonOpts);
return jsonA == jsonB;
#endif
}
}