From c1ae46fc66cb4fe13b25e1dd61f056ae7ea89cc9 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 28 Feb 2026 06:33:09 -0500 Subject: [PATCH] feat(batch1): add mapped proto scan helpers with boundary tests --- .../Internal/ProtoWire.cs | 30 +++++++ .../Internal/ProtoWireTests.cs | 77 ++++++++++++++++++ porting.db | Bin 6352896 -> 6352896 bytes reports/current.md | 8 +- reports/report_d8d71ea.md | 37 +++++++++ 5 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/ProtoWireTests.cs create mode 100644 reports/report_d8d71ea.md diff --git a/dotnet/src/ZB.MOM.NatsNet.Server/Internal/ProtoWire.cs b/dotnet/src/ZB.MOM.NatsNet.Server/Internal/ProtoWire.cs index 22eaff2..035e0c4 100644 --- a/dotnet/src/ZB.MOM.NatsNet.Server/Internal/ProtoWire.cs +++ b/dotnet/src/ZB.MOM.NatsNet.Server/Internal/ProtoWire.cs @@ -51,6 +51,12 @@ public static class ProtoWire return (num, typ, sizeTag + sizeValue, null); } + /// + /// Compatibility mapped entrypoint for PortTracker: protoScanField. + /// + public static (int num, int typ, int size, Exception? err) ProtoScanField(ReadOnlySpan b) + => ScanField(b); + /// /// Reads a protobuf tag varint and returns field number, wire type, and bytes consumed. /// Mirrors protoScanTag. @@ -71,6 +77,12 @@ public static class ProtoWire return (num, typ, size, null); } + /// + /// Compatibility mapped entrypoint for PortTracker: protoScanTag. + /// + public static (int num, int typ, int size, Exception? err) ProtoScanTag(ReadOnlySpan b) + => ScanTag(b); + /// /// Returns the byte count consumed by a field value with the given wire type. /// Mirrors protoScanFieldValue. @@ -98,6 +110,12 @@ public static class ProtoWire } } + /// + /// Compatibility mapped entrypoint for PortTracker: protoScanFieldValue. + /// + public static (int size, Exception? err) ProtoScanFieldValue(int typ, ReadOnlySpan b) + => ScanFieldValue(typ, b); + // ------------------------------------------------------------------------- // Varint decode // ------------------------------------------------------------------------- @@ -170,6 +188,12 @@ public static class ProtoWire return (0, 0, ErrOverflow); } + /// + /// Compatibility mapped entrypoint for PortTracker: protoScanVarint. + /// + public static (ulong v, int size, Exception? err) ProtoScanVarint(ReadOnlySpan b) + => ScanVarint(b); + // ------------------------------------------------------------------------- // Length-delimited decode // ------------------------------------------------------------------------- @@ -190,6 +214,12 @@ public static class ProtoWire return (lenSize + (int)l, null); } + /// + /// Compatibility mapped entrypoint for PortTracker: protoScanBytes. + /// + public static (int size, Exception? err) ProtoScanBytes(ReadOnlySpan b) + => ScanBytes(b); + // ------------------------------------------------------------------------- // Varint encode // ------------------------------------------------------------------------- diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/ProtoWireTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/ProtoWireTests.cs new file mode 100644 index 0000000..45b5048 --- /dev/null +++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/ProtoWireTests.cs @@ -0,0 +1,77 @@ +// Copyright 2012-2025 The NATS Authors +// Licensed under the Apache License, Version 2.0 + +using Shouldly; +using ZB.MOM.NatsNet.Server.Internal; + +namespace ZB.MOM.NatsNet.Server.Tests.Internal; + +public class ProtoWireTests +{ + [Fact] + public void ProtoScanTag_ValidTag_ReturnsFieldTypeAndSize() + { + var (num, typ, size, err) = ProtoWire.ProtoScanTag([0x7A]); // field=15, type=2 + + err.ShouldBeNull(); + num.ShouldBe(15); + typ.ShouldBe(2); + size.ShouldBe(1); + } + + [Fact] + public void ProtoScanTag_InvalidFieldNumber_ReturnsError() + { + var (_, _, _, err) = ProtoWire.ProtoScanTag([0x02]); // field=0, type=2 + + err.ShouldNotBeNull(); + err.Message.ShouldContain("invalid field number"); + } + + [Fact] + public void ProtoScanFieldValue_UnsupportedWireType_ReturnsError() + { + var (_, err) = ProtoWire.ProtoScanFieldValue(3, [0x01]); + + err.ShouldNotBeNull(); + err.Message.ShouldContain("unsupported type"); + } + + [Fact] + public void ProtoScanVarint_InsufficientData_ReturnsError() + { + var (_, _, err) = ProtoWire.ProtoScanVarint([0x80]); + + err.ShouldNotBeNull(); + err.Message.ShouldContain("insufficient data"); + } + + [Fact] + public void ProtoScanVarint_Overflow_ReturnsError() + { + var (_, _, err) = ProtoWire.ProtoScanVarint([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02]); + + err.ShouldNotBeNull(); + err.Message.ShouldContain("too much data"); + } + + [Fact] + public void ProtoScanBytes_LengthDelimited_ReturnsLengthPrefixPlusPayloadSize() + { + var (size, err) = ProtoWire.ProtoScanBytes([0x03, (byte)'a', (byte)'b', (byte)'c']); + + err.ShouldBeNull(); + size.ShouldBe(4); + } + + [Fact] + public void ProtoScanField_ValidLengthDelimited_ReturnsTotalFieldSize() + { + var (num, typ, size, err) = ProtoWire.ProtoScanField([0x0A, 0x03, (byte)'a', (byte)'b', (byte)'c']); // field=1,type=2 + + err.ShouldBeNull(); + num.ShouldBe(1); + typ.ShouldBe(2); + size.ShouldBe(5); + } +} diff --git a/porting.db b/porting.db index 5cda9e2a044d2cb37fd4f14c633ba681b47dcfac..3e27d6e2160bbfddd1957fac1a6b2c3304567edf 100644 GIT binary patch delta 1969 zcmciATWDK#90%}o$w`xwoRjprx;7^#IZ2ya+g!RX%Q{=TwqED5bz9xEYHUs~x+XD6 z)rW!&1M|><9RvR$sI5#?7;PTZ^VV6x4F-EqQDnXhFE4^a)EA+O-^P(8kk>7T5B$E# z`SJVn`)B#qId&OJYklp#<5TvT9f%yfDob5_l(yxVl0@>P-x zsk4$4B(aj5+ULL0qhs_hgbOn7XqSUbm^SctKIB%0Y0-WUF<%&TroSkWNITX&+Km{~ zO%GBOHJ(&w)NEEw@@}MPCApA%m82kbR+1A*)PjS|B~>qewEJi`*BRa%HnOcuF2DE! z?-t*nJmt!TN-9?hs+Mx)M8%gYN3m^#0ak0<(EahU)AX5%GSBj-jLU`&PS($IKUiMU z6~!COzx0=)LVKtSR$E-;eR`-P?Rc&CbuvW4o@Jq|_v5O>z`Rnyt_XP0$Q2 z&TkN{*^`v@2`Ur0~`%t1IeC64*fo2RK0i7r3Ddy1@fp@PQu!&;z~D2SEry7$VRQ z`(Oa}Llh1`3=YB|9D)a72!`Py7=gnu3S%%155ptyC_Dy_!xL}>o`jbS@SS2Z_Zu zHD}xX*GJIkuhZzN(-=C?U)$)b)2P&I3=NbUJO7_JxZ*80=4y^gzB+iO$5M0BXr#8y zQ?D&#pXwm1-o~cd-hKP4&uU-kF83a7EhyF7DSXd($+CY+SV-jO(ln<&ziG{9HPjlM|_=oL6)CoSad!a^`Fz6%K|6dV=Aea8wS3 zVv$fR*k7=(bk&*bBKLl-yUtwYKFoF1nd`g{bCo)C9e3xRyeIctEP1EkS$Iw>d7qD8 F{SP%vU|0YE delta 908 zcmX}oT}YEr9LMqJb=$K&dwiTa)7s-UOk%q-v!<-PgWIfO`eKWnA#PmUcZn{d`yAF_cZLWCFoFprFoOkTh`do~ zcSh9slCa7t3@NQuoitrlOIgwvtqzdH4$e&sHnp8yB&!YTw_r_-3ejML7>I>9utPj- zfdoi|t*{Lov?fNIy_pi#s60{Z)*ktT<-Pftv|^g&ZnIaIIpdnqW+)I_gl4`g@&|Y6 zR9I`WlDP@3oPQ^jS7fpt(yB1+HALK$F?1nv%4+T&N zd!Y!5VIP!0DeQ+bH~{5P0SBQH4#8nK0##5AN1+CeK`qolJv2Zg9ETIo1SjDXG{fmh tL2v1`OOnn+#VJASFRM@Pv%IsEm