📄 lib/tests/StandardHeaderTests.cs
using SharpDlt.Headers;
using Shouldly;
using Xunit;

namespace SharpDlt.Tests;

public class StandardHeaderTests
{
    [Fact]
    public void Parse_MinimalHeader()
    {
        var data = TestDlt.StandardHeader(length: 4, messageCounter: 7);

        var header = StandardHeader.Parse(data);

        header.UseExtendedHeader.ShouldBeFalse();
        header.MsbFirst.ShouldBeFalse();
        header.VersionNumber.ShouldBe(1);
        header.MessageCounter.ShouldBe((byte)7);
        header.Length.ShouldBe((ushort)4);
        header.EcuId.ShouldBeNull();
        header.SessionId.ShouldBeNull();
        header.Timestamp.ShouldBeNull();
        header.ByteLength.ShouldBe(4);
    }

    [Fact]
    public void Parse_AllOptionalFields()
    {
        var data = TestDlt.StandardHeader(
            useExtendedHeader: true,
            msbFirst: true,
            versionNumber: 1,
            messageCounter: 42,
            length: 16,
            ecuId: "ECU1",
            sessionId: 0x11223344,
            timestamp: 0x55667788
        );

        var header = StandardHeader.Parse(data);

        header.UseExtendedHeader.ShouldBeTrue();
        header.MsbFirst.ShouldBeTrue();
        header.EcuId.ShouldBe("ECU1");
        header.SessionId.ShouldBe(0x11223344u);
        header.Timestamp.ShouldBe(0x55667788u);
        header.ByteLength.ShouldBe(16);
        header.WithEcuId.ShouldBeTrue();
        header.WithSessionId.ShouldBeTrue();
        header.WithTimestamp.ShouldBeTrue();
    }

    [Theory]
    [InlineData(false, false, null, null, null, 4)]
    [InlineData(false, false, "ECU1", null, null, 8)]
    [InlineData(true, true, "ECU1", 1u, null, 12)]
    [InlineData(true, true, "ECU1", 1u, 2u, 16)]
    public void Parse_RoundTripsHeaderType(
        bool useExtendedHeader,
        bool msbFirst,
        string? ecuId,
        uint? sessionId,
        uint? timestamp,
        int expectedByteLength
    )
    {
        var data = TestDlt.StandardHeader(
            useExtendedHeader,
            msbFirst,
            ecuId: ecuId,
            sessionId: sessionId,
            timestamp: timestamp
        );

        var header = StandardHeader.Parse(data);

        header.ByteLength.ShouldBe(expectedByteLength);
        header.HeaderType.ShouldBe(data[0]);
    }

    [Fact]
    public void Parse_LengthIsBigEndian()
    {
        var data = TestDlt.StandardHeader(length: 0x0102);

        StandardHeader.Parse(data).Length.ShouldBe((ushort)0x0102);
        data[2].ShouldBe((byte)0x01);
        data[3].ShouldBe((byte)0x02);
    }

    [Fact]
    public void ReadMessageLength_ReadsLengthWithoutParsingTheHeader()
    {
        var data = TestDlt.StandardHeader(length: 0x0123, ecuId: "ECU1");

        StandardHeader.ReadMessageLength(data).ShouldBe((ushort)0x0123);
    }

    [Fact]
    public void Parse_TooShortData_Throws()
    {
        Should.Throw<DltParseException>(() => StandardHeader.Parse(new byte[3]));
    }

    [Fact]
    public void Parse_OptionalFieldsAnnouncedButMissing_Throws()
    {
        var data = TestDlt.StandardHeader(ecuId: "ECU1", timestamp: 1)[..8];

        Should.Throw<DltParseException>(() => StandardHeader.Parse(data));
    }
}