using AyCode.Core.Extensions; using AyCode.Core.Tests.TestModels; using BenchmarkDotNet.Attributes; using Newtonsoft.Json; using System.Text; namespace AyCode.Core.Benchmarks; /// /// Serialization benchmarks comparing AcJsonSerializer/Deserializer with Newtonsoft.Json. /// Uses shared TestModels from AyCode.Core.Tests for consistency. /// [MemoryDiagnoser] public class SerializationBenchmarks { // Test data - uses shared TestModels private TestOrder _testOrder = null!; // Pre-serialized JSON for deserialization benchmarks private string _newtonsoftJson = null!; private string _ayCodeJson = null!; // Target objects for Populate benchmarks private TestOrder _populateTarget = null!; // Settings private JsonSerializerSettings _newtonsoftNoRefSettings = null!; private JsonSerializerSettings _ayCodeSettings = null!; [GlobalSetup] public void Setup() { // Newtonsoft WITHOUT reference handling (baseline) _newtonsoftNoRefSettings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore, Formatting = Formatting.None }; // AyCode WITH reference handling _ayCodeSettings = SerializeObjectExtensions.Options; // Create benchmark data using shared factory // ~1500 objects: 5 items × 4 pallets × 3 measurements × 5 points = 300 points + containers _testOrder = TestDataFactory.CreateBenchmarkOrder( itemCount: 5, palletsPerItem: 4, measurementsPerPallet: 3, pointsPerMeasurement: 5); // Pre-serialize for deserialization benchmarks _newtonsoftJson = JsonConvert.SerializeObject(_testOrder, _newtonsoftNoRefSettings); _ayCodeJson = _testOrder.ToJson(_ayCodeSettings); // Create target for populate benchmarks _populateTarget = new TestOrder(); // Output sizes for comparison var newtonsoftBytes = Encoding.UTF8.GetByteCount(_newtonsoftJson); var ayCodeBytes = Encoding.UTF8.GetByteCount(_ayCodeJson); Console.WriteLine("=== JSON Size Comparison ==="); Console.WriteLine($"Newtonsoft (skip defaults): {_newtonsoftJson.Length:N0} chars ({newtonsoftBytes:N0} bytes)"); Console.WriteLine($"AyCode (refs+skip): {_ayCodeJson.Length:N0} chars ({ayCodeBytes:N0} bytes)"); Console.WriteLine($"Size reduction: {(1.0 - (double)ayCodeBytes / newtonsoftBytes) * 100:F1}%"); } #region Serialization Benchmarks [Benchmark(Description = "Newtonsoft (no refs)")] [BenchmarkCategory("Serialize")] public string Serialize_Newtonsoft_NoRefs() => JsonConvert.SerializeObject(_testOrder, _newtonsoftNoRefSettings); [Benchmark(Description = "AyCode (with refs)")] [BenchmarkCategory("Serialize")] public string Serialize_AyCode_WithRefs() => _testOrder.ToJson(_ayCodeSettings); [Benchmark(Description = "AcJsonSerializer (custom)")] [BenchmarkCategory("Serialize")] public string Serialize_AcJsonSerializer() => AcJsonSerializer.Serialize(_testOrder); #endregion #region Deserialization Benchmarks [Benchmark(Description = "Newtonsoft (no refs)")] [BenchmarkCategory("Deserialize")] public TestOrder? Deserialize_Newtonsoft_NoRefs() => JsonConvert.DeserializeObject(_newtonsoftJson, _newtonsoftNoRefSettings); [Benchmark(Description = "AyCode (with refs)")] [BenchmarkCategory("Deserialize")] public TestOrder? Deserialize_AyCode_WithRefs() => _ayCodeJson.JsonTo(_ayCodeSettings); [Benchmark(Description = "AcJsonDeserializer (custom)")] [BenchmarkCategory("Deserialize")] public TestOrder? Deserialize_AcJsonDeserializer() => AcJsonDeserializer.Deserialize(_ayCodeJson); #endregion #region Populate Benchmarks [Benchmark(Description = "AcJsonDeserializer.Populate")] [BenchmarkCategory("Populate")] public void Populate_AcJsonDeserializer() { // Create fresh target for each iteration to avoid state pollution var target = new TestOrder(); AcJsonDeserializer.Populate(_ayCodeJson, target); } [Benchmark(Description = "Newtonsoft PopulateObject")] [BenchmarkCategory("Populate")] public void Populate_Newtonsoft() { // Create fresh target for each iteration to match the other benchmark var target = new TestOrder(); JsonConvert.PopulateObject(_newtonsoftJson, target, _newtonsoftNoRefSettings); } #endregion #region JSON Size Comparison [Benchmark(Description = "JSON Size - Newtonsoft")] [BenchmarkCategory("Size")] public int JsonSize_Newtonsoft() => _newtonsoftJson.Length; [Benchmark(Description = "JSON Size - AyCode")] [BenchmarkCategory("Size")] public int JsonSize_AyCode() => _ayCodeJson.Length; #endregion }