📄 lib/tests/DltMessageTests.cs
using System.Linq;
using SharpDlt.Headers;
using SharpDlt.Payloads;
using Shouldly;
using Xunit;

namespace SharpDlt.Tests;

public class DltMessageTests
{
    [Fact]
    public void Parse_VerboseMessageWithStorageHeader()
    {
        var data = TestDlt.VerboseMessage([TestDlt.StringArgument("hello")], timestamp: 12_3456);

        var message = DltMessage.Parse(data);

        message.StorageHeader.ShouldNotBeNull().EcuId.ShouldBe("ECU1");
        message.StandardHeader.UseExtendedHeader.ShouldBeTrue();
        message.StandardHeader.Timestamp.ShouldBe(123_456u);
        message.ExtendedHeader.ShouldNotBeNull().ApplicationId.ShouldBe("APP1");
        message.IsVerbose.ShouldBeTrue();
        message
            .VerbosePayload.ShouldNotBeNull()
            .Arguments.ShouldHaveSingleItem()
            .ShouldBe(new DltStringArgument("hello", DltStringCoding.Ascii));
        message.NonVerbosePayload.ShouldBeNull();
    }

    [Fact]
    public void Parse_WithoutStorageHeader()
    {
        var data = TestDlt.VerboseMessage([TestDlt.StringArgument("x")], withStorageHeader: false);

        var message = DltMessage.Parse(data, new DltReaderOptions { HasStorageHeader = false });

        message.StorageHeader.ShouldBeNull();
        message.VerbosePayload.ShouldNotBeNull().Arguments.Count.ShouldBe(1);
    }

    [Fact]
    public void Parse_NonVerboseMessage()
    {
        var data = TestDlt.Message(
            TestDlt.StorageHeader(),
            TestDlt.StandardHeader(useExtendedHeader: true),
            TestDlt.ExtendedHeader(
                verbose: false,
                messageType: DltMessageType.Control,
                messageTypeInfo: (byte)DltControlInfo.Response,
                numberOfArguments: 0
            ),
            [.. TestDlt.LittleEndian(42), 0xAB]
        );

        var message = DltMessage.Parse(data);

        message.IsVerbose.ShouldBeFalse();
        var payload = message.NonVerbosePayload.ShouldNotBeNull();
        payload.MessageId.ShouldBe(42u);
        payload.NonStaticData.ToArray().ShouldBe(new byte[] { 0xAB });
    }

    [Fact]
    public void Parse_MessageWithoutExtendedHeaderAndWithoutPayload()
    {
        var data = TestDlt.Message(TestDlt.StorageHeader(), TestDlt.StandardHeader());

        var message = DltMessage.Parse(data);

        message.ExtendedHeader.ShouldBeNull();
        message.Payload.ShouldBeNull();
        message.IsVerbose.ShouldBeFalse();
    }

    [Fact]
    public void Parse_BigEndianPayload()
    {
        var data = TestDlt.VerboseMessage(
            [TestDlt.Argument(TestDlt.TypeInfoUInt32, [0x00, 0x01, 0x00, 0x00], msbFirst: true)],
            msbFirst: true
        );

        var message = DltMessage.Parse(data);

        message.StandardHeader.MsbFirst.ShouldBeTrue();
        message
            .VerbosePayload.ShouldNotBeNull()
            .Arguments[0]
            .ShouldBe(new DltUnsignedArgument(65536, DltIntegerWidth.Bits32));
    }

    [Fact]
    public void Parse_IgnoresDataBeyondTheDeclaredMessageLength()
    {
        var data = TestDlt.VerboseMessage([TestDlt.StringArgument("hi")]).Concat<byte>([0xFF, 0xFF, 0xFF]).ToArray();

        var message = DltMessage.Parse(data);

        message
            .VerbosePayload.ShouldNotBeNull()
            .Arguments.ShouldHaveSingleItem()
            .ShouldBe(new DltStringArgument("hi", DltStringCoding.Ascii));
    }

    [Fact]
    public void ToString_DescribesTheMessage()
    {
        var data = TestDlt.Message(
            TestDlt.StorageHeader(seconds: 1_600_000_000, microseconds: 123, ecuId: "ECU1"),
            TestDlt.StandardHeader(useExtendedHeader: true, messageCounter: 9, timestamp: 12_345),
            TestDlt.ExtendedHeader(messageType: DltMessageType.Log, messageTypeInfo: (byte)DltLogInfo.Warn),
            TestDlt.StringArgument("hello")
        );

        DltMessage
            .Parse(data)
            .ToString()
            .ShouldBe("2020/09/13 12:26:40.000123 1.2345 9 ECU1 APP1 CTX1 log warn verbose 1 hello");
    }

    [Fact]
    public void ToString_NonVerboseWithoutStorageHeader()
    {
        var data = TestDlt.Message(
            null,
            TestDlt.StandardHeader(useExtendedHeader: true, messageCounter: 3, sessionId: 7),
            TestDlt.ExtendedHeader(
                verbose: false,
                messageType: DltMessageType.Control,
                messageTypeInfo: (byte)DltControlInfo.Request,
                numberOfArguments: 0
            ),
            TestDlt.LittleEndian(5)
        );

        DltMessage
            .Parse(data, new DltReaderOptions { HasStorageHeader = false })
            .ToString()
            .ShouldBe("3 APP1 CTX1 7 control request non-verbose 0 [5] ");
    }

    [Fact]
    public void Parse_MalformedData_Throws()
    {
        Should.Throw<DltParseException>(() => DltMessage.Parse(new byte[10]));
    }

    [Fact]
    public void Equality_IsByValue()
    {
        var data = TestDlt.VerboseMessage([TestDlt.StringArgument("hello")]);

        DltMessage.Parse(data).ShouldBe(DltMessage.Parse(data));
    }
}