// 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); } [Theory] [InlineData(1UL << 7, 2)] [InlineData(1UL << 14, 3)] [InlineData(1UL << 21, 4)] [InlineData(1UL << 28, 5)] [InlineData(1UL << 35, 6)] [InlineData(1UL << 42, 7)] [InlineData(1UL << 49, 8)] [InlineData(1UL << 56, 9)] [InlineData(1UL << 63, 10)] public void ProtoEncodeVarint_BoundaryValues_ReturnsExpectedLength(ulong value, int expectedLength) { var encoded = ProtoWire.ProtoEncodeVarint(value); encoded.Length.ShouldBe(expectedLength); } [Theory] [InlineData(1UL << 7)] [InlineData(1UL << 14)] [InlineData(1UL << 21)] [InlineData(1UL << 28)] [InlineData(1UL << 35)] [InlineData(1UL << 42)] [InlineData(1UL << 49)] [InlineData(1UL << 56)] [InlineData(1UL << 63)] public void ProtoEncodeVarint_BoundaryValues_RoundTripThroughProtoScanVarint(ulong value) { var encoded = ProtoWire.ProtoEncodeVarint(value); var (decoded, size, err) = ProtoWire.ProtoScanVarint(encoded); err.ShouldBeNull(); size.ShouldBe(encoded.Length); decoded.ShouldBe(value); } }