using System.Text; using NATS.Server.Mqtt; namespace NATS.Server.Mqtt.Tests.Mqtt; public class MqttProtocolConstantsParityBatch1Tests { [Fact] public void Constants_match_mqtt_go_reference_values() { MqttProtocolConstants.SubscribeFlags.ShouldBe((byte)0x02); MqttProtocolConstants.ConnAckAccepted.ShouldBe((byte)0x00); MqttProtocolConstants.ConnAckUnacceptableProtocolVersion.ShouldBe((byte)0x01); MqttProtocolConstants.ConnAckIdentifierRejected.ShouldBe((byte)0x02); MqttProtocolConstants.ConnAckServerUnavailable.ShouldBe((byte)0x03); MqttProtocolConstants.ConnAckBadUserNameOrPassword.ShouldBe((byte)0x04); MqttProtocolConstants.ConnAckNotAuthorized.ShouldBe((byte)0x05); MqttProtocolConstants.MaxPayloadSize.ShouldBe(268_435_455); MqttProtocolConstants.DefaultAckWait.ShouldBe(TimeSpan.FromSeconds(30)); MqttProtocolConstants.MaxAckTotalLimit.ShouldBe(0xFFFF); } [Fact] public void ParseSubscribe_accepts_required_subscribe_flags() { var payload = CreateSubscribePayload(packetId: 7, ("sport/tennis/#", 1)); var info = MqttBinaryDecoder.ParseSubscribe(payload, flags: MqttProtocolConstants.SubscribeFlags); info.PacketId.ShouldBe((ushort)7); info.Filters.Count.ShouldBe(1); info.Filters[0].TopicFilter.ShouldBe("sport/tennis/#"); info.Filters[0].QoS.ShouldBe((byte)1); } [Fact] public void ParseSubscribe_rejects_invalid_subscribe_flags() { var payload = CreateSubscribePayload(packetId: 5, ("topic/one", 0)); var ex = Should.Throw(() => MqttBinaryDecoder.ParseSubscribe(payload, flags: 0x00)); ex.Message.ShouldContain("invalid fixed-header flags"); } private static byte[] CreateSubscribePayload(ushort packetId, params (string Topic, byte Qos)[] filters) { using var ms = new MemoryStream(); using var writer = new BinaryWriter(ms); WriteUInt16BigEndian(writer, packetId); foreach (var (topic, qos) in filters) { WriteString(writer, topic); writer.Write(qos); } return ms.ToArray(); } private static void WriteString(BinaryWriter writer, string value) { var bytes = Encoding.UTF8.GetBytes(value); WriteUInt16BigEndian(writer, (ushort)bytes.Length); writer.Write(bytes); } private static void WriteUInt16BigEndian(BinaryWriter writer, ushort value) { writer.Write((byte)(value >> 8)); writer.Write((byte)(value & 0xFF)); } }