From 511d4be31ff03a63699e107a5e2e0106244d2bde Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 10:28:00 +0000 Subject: [PATCH 1/6] Add Foo and Bar roundtrip test with hardcoded size checks - Define Foo and Bar structs with [StructLayout(LayoutKind.Sequential, Pack = 1)] and [ZeroSerializer] attributes in SerializationModels.cs. - Add SequentialPackOneFooBarRoundTrip test in SerializationTests.cs verifying exact hardcoded byte lengths (3 for BarView and 30 for FooView) and verifying roundtrip data integrity. --- tests/SerializationModels.cs | 22 +++++++++++++++++++++ tests/SerializationTests.cs | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/tests/SerializationModels.cs b/tests/SerializationModels.cs index 6a8dfad..f0f6e02 100644 --- a/tests/SerializationModels.cs +++ b/tests/SerializationModels.cs @@ -294,6 +294,28 @@ public struct StrictBlittableStruct public int Value { get; init; } } +[StructLayout(LayoutKind.Sequential, Pack = 1)] +[ZeroSerializer] +public struct Bar +{ + public byte A { get; set; } + public short B { get; set; } +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +[ZeroSerializer] +public struct Foo +{ + public byte A { get; set; } + public long B { get; set; } + public byte C { get; set; } + public int D { get; set; } + public short E { get; set; } + public double F { get; set; } + public Bar G { get; set; } + public Bar H { get; set; } +} + [ZeroSerializer] public record SimpleCsharpRecord { diff --git a/tests/SerializationTests.cs b/tests/SerializationTests.cs index fc25670..c20509c 100644 --- a/tests/SerializationTests.cs +++ b/tests/SerializationTests.cs @@ -1228,4 +1228,41 @@ public void BlittableRecordStructNestedPropertyRoundTrip() TestAssert.True(viewNulls.Values.IsEmpty, nameof(viewNulls.Values.IsEmpty)); TestAssert.Equal(writtenBytesNulls, viewNulls.GetByteLength(), "Nulls GetByteLength"); } + + [Fact] + public void SequentialPackOneFooBarRoundTrip() + { + TestAssert.Equal(3, BarView.RequiredByteLength, nameof(BarView.RequiredByteLength)); + TestAssert.Equal(30, FooView.RequiredByteLength, nameof(FooView.RequiredByteLength)); + + var foo = new Foo + { + A = 0x12, + B = 0x123456789ABCDEF0, + C = 0x34, + D = 0x56789ABC, + E = -1234, + F = 3.141592653589793, + G = new Bar { A = 0xAB, B = 0x5678 }, + H = new Bar { A = 0xCD, B = -4321 } + }; + + var buffer = new byte[FooView.RequiredByteLength]; + int writtenBytes = foo.Serialize(buffer); + + TestAssert.Equal(30, writtenBytes, nameof(writtenBytes)); + + var view = new FooView(buffer); + + TestAssert.Equal(foo.A, view.A, nameof(view.A)); + TestAssert.Equal(foo.B, view.B, nameof(view.B)); + TestAssert.Equal(foo.C, view.C, nameof(view.C)); + TestAssert.Equal(foo.D, view.D, nameof(view.D)); + TestAssert.Equal(foo.E, view.E, nameof(view.E)); + TestAssert.Equal(foo.F, view.F, nameof(view.F)); + TestAssert.Equal(foo.G.A, view.G.A, nameof(view.G.A)); + TestAssert.Equal(foo.G.B, view.G.B, nameof(view.G.B)); + TestAssert.Equal(foo.H.A, view.H.A, nameof(view.H.A)); + TestAssert.Equal(foo.H.B, view.H.B, nameof(view.H.B)); + } } From ca01f3d777c222fd43edd9dd6d6d252e203ccf0c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 10:44:29 +0000 Subject: [PATCH 2/6] Update Foo struct layout and roundtrip test per PR feedback - Updated Foo struct in SerializationModels.cs to include byte property G and Bar properties H and I as suggested in PR review. - Updated SequentialPackOneFooBarRoundTrip in SerializationTests.cs to check expected byte lengths (3 for BarView and 31 for FooView) and full roundtrip serialization. --- tests/SerializationModels.cs | 3 ++- tests/SerializationTests.cs | 14 ++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/SerializationModels.cs b/tests/SerializationModels.cs index f0f6e02..56ba4fb 100644 --- a/tests/SerializationModels.cs +++ b/tests/SerializationModels.cs @@ -312,8 +312,9 @@ public struct Foo public int D { get; set; } public short E { get; set; } public double F { get; set; } - public Bar G { get; set; } + public byte G { get; set; } public Bar H { get; set; } + public Bar I { get; set; } } [ZeroSerializer] diff --git a/tests/SerializationTests.cs b/tests/SerializationTests.cs index c20509c..88202db 100644 --- a/tests/SerializationTests.cs +++ b/tests/SerializationTests.cs @@ -1233,7 +1233,7 @@ public void BlittableRecordStructNestedPropertyRoundTrip() public void SequentialPackOneFooBarRoundTrip() { TestAssert.Equal(3, BarView.RequiredByteLength, nameof(BarView.RequiredByteLength)); - TestAssert.Equal(30, FooView.RequiredByteLength, nameof(FooView.RequiredByteLength)); + TestAssert.Equal(31, FooView.RequiredByteLength, nameof(FooView.RequiredByteLength)); var foo = new Foo { @@ -1243,14 +1243,15 @@ public void SequentialPackOneFooBarRoundTrip() D = 0x56789ABC, E = -1234, F = 3.141592653589793, - G = new Bar { A = 0xAB, B = 0x5678 }, - H = new Bar { A = 0xCD, B = -4321 } + G = 0x77, + H = new Bar { A = 0xAB, B = 0x5678 }, + I = new Bar { A = 0xCD, B = -4321 } }; var buffer = new byte[FooView.RequiredByteLength]; int writtenBytes = foo.Serialize(buffer); - TestAssert.Equal(30, writtenBytes, nameof(writtenBytes)); + TestAssert.Equal(31, writtenBytes, nameof(writtenBytes)); var view = new FooView(buffer); @@ -1260,9 +1261,10 @@ public void SequentialPackOneFooBarRoundTrip() TestAssert.Equal(foo.D, view.D, nameof(view.D)); TestAssert.Equal(foo.E, view.E, nameof(view.E)); TestAssert.Equal(foo.F, view.F, nameof(view.F)); - TestAssert.Equal(foo.G.A, view.G.A, nameof(view.G.A)); - TestAssert.Equal(foo.G.B, view.G.B, nameof(view.G.B)); + TestAssert.Equal(foo.G, view.G, nameof(view.G)); TestAssert.Equal(foo.H.A, view.H.A, nameof(view.H.A)); TestAssert.Equal(foo.H.B, view.H.B, nameof(view.H.B)); + TestAssert.Equal(foo.I.A, view.I.A, nameof(view.I.A)); + TestAssert.Equal(foo.I.B, view.I.B, nameof(view.I.B)); } } From cbfca1413007e81f98e0551054afaa4bcbd4589f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 10:46:56 +0000 Subject: [PATCH 3/6] Rename Bar struct to BadAlignedStructWithPackOne per PR review - Renamed Bar struct to BadAlignedStructWithPackOne in SerializationModels.cs and updated Foo struct properties H and I accordingly. - Renamed test method to BadAlignedStructWithPackOneRoundTrip in SerializationTests.cs. --- tests/SerializationModels.cs | 6 +++--- tests/SerializationTests.cs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/SerializationModels.cs b/tests/SerializationModels.cs index 56ba4fb..239faa9 100644 --- a/tests/SerializationModels.cs +++ b/tests/SerializationModels.cs @@ -296,7 +296,7 @@ public struct StrictBlittableStruct [StructLayout(LayoutKind.Sequential, Pack = 1)] [ZeroSerializer] -public struct Bar +public struct BadAlignedStructWithPackOne { public byte A { get; set; } public short B { get; set; } @@ -313,8 +313,8 @@ public struct Foo public short E { get; set; } public double F { get; set; } public byte G { get; set; } - public Bar H { get; set; } - public Bar I { get; set; } + public BadAlignedStructWithPackOne H { get; set; } + public BadAlignedStructWithPackOne I { get; set; } } [ZeroSerializer] diff --git a/tests/SerializationTests.cs b/tests/SerializationTests.cs index 88202db..9cdbcc6 100644 --- a/tests/SerializationTests.cs +++ b/tests/SerializationTests.cs @@ -1230,9 +1230,9 @@ public void BlittableRecordStructNestedPropertyRoundTrip() } [Fact] - public void SequentialPackOneFooBarRoundTrip() + public void BadAlignedStructWithPackOneRoundTrip() { - TestAssert.Equal(3, BarView.RequiredByteLength, nameof(BarView.RequiredByteLength)); + TestAssert.Equal(3, BadAlignedStructWithPackOneView.RequiredByteLength, nameof(BadAlignedStructWithPackOneView.RequiredByteLength)); TestAssert.Equal(31, FooView.RequiredByteLength, nameof(FooView.RequiredByteLength)); var foo = new Foo @@ -1244,8 +1244,8 @@ public void SequentialPackOneFooBarRoundTrip() E = -1234, F = 3.141592653589793, G = 0x77, - H = new Bar { A = 0xAB, B = 0x5678 }, - I = new Bar { A = 0xCD, B = -4321 } + H = new BadAlignedStructWithPackOne { A = 0xAB, B = 0x5678 }, + I = new BadAlignedStructWithPackOne { A = 0xCD, B = -4321 } }; var buffer = new byte[FooView.RequiredByteLength]; From 965f5869262a7ed94885a6b6bfde58b058588fac Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 11:22:49 +0000 Subject: [PATCH 4/6] Rename Foo and Bar struct models per PR review - Renamed Foo to BadAlignedContainerStructWithPackOne and Bar to BadAlignedStructWithPackOne in SerializationModels.cs and updated SerializationTests.cs accordingly. --- tests/SerializationModels.cs | 2 +- tests/SerializationTests.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/SerializationModels.cs b/tests/SerializationModels.cs index 239faa9..d9b2295 100644 --- a/tests/SerializationModels.cs +++ b/tests/SerializationModels.cs @@ -304,7 +304,7 @@ public struct BadAlignedStructWithPackOne [StructLayout(LayoutKind.Sequential, Pack = 1)] [ZeroSerializer] -public struct Foo +public struct BadAlignedContainerStructWithPackOne { public byte A { get; set; } public long B { get; set; } diff --git a/tests/SerializationTests.cs b/tests/SerializationTests.cs index 9cdbcc6..ae4d4b3 100644 --- a/tests/SerializationTests.cs +++ b/tests/SerializationTests.cs @@ -1233,9 +1233,9 @@ public void BlittableRecordStructNestedPropertyRoundTrip() public void BadAlignedStructWithPackOneRoundTrip() { TestAssert.Equal(3, BadAlignedStructWithPackOneView.RequiredByteLength, nameof(BadAlignedStructWithPackOneView.RequiredByteLength)); - TestAssert.Equal(31, FooView.RequiredByteLength, nameof(FooView.RequiredByteLength)); + TestAssert.Equal(31, BadAlignedContainerStructWithPackOneView.RequiredByteLength, nameof(BadAlignedContainerStructWithPackOneView.RequiredByteLength)); - var foo = new Foo + var foo = new BadAlignedContainerStructWithPackOne { A = 0x12, B = 0x123456789ABCDEF0, @@ -1248,12 +1248,12 @@ public void BadAlignedStructWithPackOneRoundTrip() I = new BadAlignedStructWithPackOne { A = 0xCD, B = -4321 } }; - var buffer = new byte[FooView.RequiredByteLength]; + var buffer = new byte[BadAlignedContainerStructWithPackOneView.RequiredByteLength]; int writtenBytes = foo.Serialize(buffer); TestAssert.Equal(31, writtenBytes, nameof(writtenBytes)); - var view = new FooView(buffer); + var view = new BadAlignedContainerStructWithPackOneView(buffer); TestAssert.Equal(foo.A, view.A, nameof(view.A)); TestAssert.Equal(foo.B, view.B, nameof(view.B)); From 0c788ac3d0126f0a424b0fc2c47a85aab0a3878c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 21:43:24 +0000 Subject: [PATCH 5/6] Update struct names and add Materialize assertion per PR review - Renamed BadAlignedStructWithPackOne to BadlyAlignedStructWithPackOne and BadAlignedContainerStructWithPackOne to BadlyAlignedContainerStructWithPackOne as record structs. - Added Materialize equality assertion (foo == view.Materialize()) to BadlyAlignedStructWithPackOneRoundTrip in SerializationTests.cs. --- tests/SerializationModels.cs | 8 ++++---- tests/SerializationTests.cs | 17 +++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/SerializationModels.cs b/tests/SerializationModels.cs index d9b2295..b0a083b 100644 --- a/tests/SerializationModels.cs +++ b/tests/SerializationModels.cs @@ -296,7 +296,7 @@ public struct StrictBlittableStruct [StructLayout(LayoutKind.Sequential, Pack = 1)] [ZeroSerializer] -public struct BadAlignedStructWithPackOne +public record struct BadlyAlignedStructWithPackOne { public byte A { get; set; } public short B { get; set; } @@ -304,7 +304,7 @@ public struct BadAlignedStructWithPackOne [StructLayout(LayoutKind.Sequential, Pack = 1)] [ZeroSerializer] -public struct BadAlignedContainerStructWithPackOne +public record struct BadlyAlignedContainerStructWithPackOne { public byte A { get; set; } public long B { get; set; } @@ -313,8 +313,8 @@ public struct BadAlignedContainerStructWithPackOne public short E { get; set; } public double F { get; set; } public byte G { get; set; } - public BadAlignedStructWithPackOne H { get; set; } - public BadAlignedStructWithPackOne I { get; set; } + public BadlyAlignedStructWithPackOne H { get; set; } + public BadlyAlignedStructWithPackOne I { get; set; } } [ZeroSerializer] diff --git a/tests/SerializationTests.cs b/tests/SerializationTests.cs index ae4d4b3..810cf3b 100644 --- a/tests/SerializationTests.cs +++ b/tests/SerializationTests.cs @@ -1230,12 +1230,12 @@ public void BlittableRecordStructNestedPropertyRoundTrip() } [Fact] - public void BadAlignedStructWithPackOneRoundTrip() + public void BadlyAlignedStructWithPackOneRoundTrip() { - TestAssert.Equal(3, BadAlignedStructWithPackOneView.RequiredByteLength, nameof(BadAlignedStructWithPackOneView.RequiredByteLength)); - TestAssert.Equal(31, BadAlignedContainerStructWithPackOneView.RequiredByteLength, nameof(BadAlignedContainerStructWithPackOneView.RequiredByteLength)); + TestAssert.Equal(3, BadlyAlignedStructWithPackOneView.RequiredByteLength, nameof(BadlyAlignedStructWithPackOneView.RequiredByteLength)); + TestAssert.Equal(31, BadlyAlignedContainerStructWithPackOneView.RequiredByteLength, nameof(BadlyAlignedContainerStructWithPackOneView.RequiredByteLength)); - var foo = new BadAlignedContainerStructWithPackOne + var foo = new BadlyAlignedContainerStructWithPackOne { A = 0x12, B = 0x123456789ABCDEF0, @@ -1244,16 +1244,16 @@ public void BadAlignedStructWithPackOneRoundTrip() E = -1234, F = 3.141592653589793, G = 0x77, - H = new BadAlignedStructWithPackOne { A = 0xAB, B = 0x5678 }, - I = new BadAlignedStructWithPackOne { A = 0xCD, B = -4321 } + H = new BadlyAlignedStructWithPackOne { A = 0xAB, B = 0x5678 }, + I = new BadlyAlignedStructWithPackOne { A = 0xCD, B = -4321 } }; - var buffer = new byte[BadAlignedContainerStructWithPackOneView.RequiredByteLength]; + var buffer = new byte[BadlyAlignedContainerStructWithPackOneView.RequiredByteLength]; int writtenBytes = foo.Serialize(buffer); TestAssert.Equal(31, writtenBytes, nameof(writtenBytes)); - var view = new BadAlignedContainerStructWithPackOneView(buffer); + var view = new BadlyAlignedContainerStructWithPackOneView(buffer); TestAssert.Equal(foo.A, view.A, nameof(view.A)); TestAssert.Equal(foo.B, view.B, nameof(view.B)); @@ -1266,5 +1266,6 @@ public void BadAlignedStructWithPackOneRoundTrip() TestAssert.Equal(foo.H.B, view.H.B, nameof(view.H.B)); TestAssert.Equal(foo.I.A, view.I.A, nameof(view.I.A)); TestAssert.Equal(foo.I.B, view.I.B, nameof(view.I.B)); + TestAssert.True(foo == view.Materialize(), nameof(view)); } } From a79de3697e135e2e446ae32ae32bdf43c5d8ecf3 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 22:53:48 +0000 Subject: [PATCH 6/6] Add BadlyAlignedContainerArrayStructWithPackOne and update roundtrip test - Added BadlyAlignedContainerArrayStructWithPackOne model in SerializationModels.cs. - Updated BadlyAlignedStructWithPackOneRoundTrip in SerializationTests.cs to test array serialization and memory slicing as requested in PR review. --- tests/SerializationModels.cs | 6 ++++++ tests/SerializationTests.cs | 19 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/SerializationModels.cs b/tests/SerializationModels.cs index b0a083b..1b0ba97 100644 --- a/tests/SerializationModels.cs +++ b/tests/SerializationModels.cs @@ -317,6 +317,12 @@ public record struct BadlyAlignedContainerStructWithPackOne public BadlyAlignedStructWithPackOne I { get; set; } } +[ZeroSerializer] +public sealed class BadlyAlignedContainerArrayStructWithPackOne +{ + public BadlyAlignedContainerStructWithPackOne[] Values { get; set; } = Array.Empty(); +} + [ZeroSerializer] public record SimpleCsharpRecord { diff --git a/tests/SerializationTests.cs b/tests/SerializationTests.cs index 810cf3b..3b493fe 100644 --- a/tests/SerializationTests.cs +++ b/tests/SerializationTests.cs @@ -1248,12 +1248,25 @@ public void BadlyAlignedStructWithPackOneRoundTrip() I = new BadlyAlignedStructWithPackOne { A = 0xCD, B = -4321 } }; - var buffer = new byte[BadlyAlignedContainerStructWithPackOneView.RequiredByteLength]; - int writtenBytes = foo.Serialize(buffer); + var array = new BadlyAlignedContainerArrayStructWithPackOne(); + array.Values = new[] { default, foo, default }; + + var arrayBuffer = new byte[1024]; + int arrayWrittenBytes = array.Serialize(arrayBuffer); + TestAssert.Equal(101, arrayWrittenBytes, nameof(arrayWrittenBytes)); + + var arrayView = new BadlyAlignedContainerArrayStructWithPackOneView(arrayBuffer); + TestAssert.True(arrayView.Values[0] == default, "1st item"); + TestAssert.True(arrayView.Values[1] == foo, "2nd item"); + TestAssert.True(arrayView.Values[2] == default, "3rd item"); + + var buffer = new byte[BadlyAlignedContainerStructWithPackOneView.RequiredByteLength * 3]; + int writtenBytes = foo.Serialize(buffer.AsSpan(BadlyAlignedContainerStructWithPackOneView.RequiredByteLength)); TestAssert.Equal(31, writtenBytes, nameof(writtenBytes)); - var view = new BadlyAlignedContainerStructWithPackOneView(buffer); + var second = buffer.AsMemory().Slice(BadlyAlignedContainerStructWithPackOneView.RequiredByteLength, BadlyAlignedContainerStructWithPackOneView.RequiredByteLength); + var view = new BadlyAlignedContainerStructWithPackOneView(second); TestAssert.Equal(foo.A, view.A, nameof(view.A)); TestAssert.Equal(foo.B, view.B, nameof(view.B));