/********************************************************************************
 * Copyright (c) 2025-2026 ZF Friedrichshafen AG
 *
 * This program and the accompanying materials are made available under the
 * terms of the Apache License Version 2.0 which is available at
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Contributors:
 *   Erik Verhoeven - initial API and implementation
 ********************************************************************************/

#include "../../include/gtest_custom.h"
#include "dbc_parser_test.h"
#include "../../../global/dbcparser/dbcparser.cpp"
#include <iostream>
#include <fstream>

void CDbcParserTest::SetUpTestCase()
{}

void CDbcParserTest::TearDownTestCase()
{}

void CDbcParserTest::SetUp()
{}

void CDbcParserTest::TearDown()
{}

TEST_F(CDbcParserTest, EmptySource)
{
    EXPECT_NO_THROW(dbc::CDbcSource());

    dbc::CDbcSource src;
    EXPECT_NO_THROW(dbc::CDbcSource dst(src));

    EXPECT_NO_THROW(dbc::CDbcSource dst(std::move(src)));
}

TEST_F(CDbcParserTest, SourceString)
{
    std::string ssEmpty;
    EXPECT_NO_THROW(dbc::CDbcSource srcEmpty(ssEmpty));

    std::string ssSourceSpace = " ";
    EXPECT_NO_THROW(dbc::CDbcSource srcSpace(ssSourceSpace));

    std::string ssSource = "VERSION \"123\"";
    EXPECT_NO_THROW(dbc::CDbcSource src(ssSource));
}

TEST_F(CDbcParserTest, SourceFile)
{
    dbc::CDbcSource src;
    EXPECT_EQ(src.Path(), std::filesystem::path(""));

    std::ofstream fstreamFileEmpty("empty.dbc", std::ios::trunc);
    fstreamFileEmpty.close();
    EXPECT_NO_THROW(dbc::CDbcSource(std::filesystem::path("empty.dbc")));
    dbc::CDbcSource srcEmpty((std::filesystem::path("empty.dbc")));
    EXPECT_EQ(srcEmpty.Path(), std::filesystem::path("empty.dbc"));
    try
    {
        std::filesystem::remove("empty.dbc");
    } catch (const std::filesystem::filesystem_error&)
    {}

    std::ofstream fstreamFile("test.dbc", std::ios::trunc);
    fstreamFile << " ";
    fstreamFile.close();
    EXPECT_NO_THROW(dbc::CDbcSource(std::filesystem::path("test.dbc")));
    try
    {
        std::filesystem::remove("test.dbc");
    } catch (const std::filesystem::filesystem_error&)
    {}

    EXPECT_THROW(dbc::CDbcSource(std::filesystem::path("not_exist")), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, SourcePosition)
{
    std::string ssEmpty;
    dbc::CDbcSource srcEmpty(ssEmpty);
    EXPECT_EQ(srcEmpty.Pos(), 0);
    EXPECT_TRUE(srcEmpty.IsEOF());

    std::string ssSource = "VERSION \"123\"";
    dbc::CDbcSource src(ssSource);
    EXPECT_EQ(src.Pos(), 0);
    EXPECT_FALSE(src.IsEOF());
    src.Pos() += 5;
    EXPECT_EQ(src.Pos(), 5);
    EXPECT_FALSE(src.IsEOF());
    src.Pos() += 8;
    EXPECT_EQ(src.Pos(), 13);
    EXPECT_TRUE(src.IsEOF());
    src.Pos() = 100;
    EXPECT_EQ(src.Pos(), 100);
    EXPECT_TRUE(src.IsEOF());
    src.ResetPos();
    EXPECT_EQ(src.Pos(), 0);
    EXPECT_FALSE(src.IsEOF());
}

TEST_F(CDbcParserTest, SourcePosLock)
{
    std::string ssSource = "VERSION \"123\"";
    dbc::CDbcSource src(ssSource);
    src.Pos() += 5;
    EXPECT_EQ(src.Pos(), 5);

    // Automatic rollback
    {
        auto sPosLock = src.CreatePosLock();
        src.Pos() += 8;
        EXPECT_EQ(src.Pos(), 13);
    }
    EXPECT_EQ(src.Pos(), 5);

    // Rollback; automatic rollback disabled
    {
        auto sPosLock = src.CreatePosLock();
        src.Pos() += 8;
        EXPECT_EQ(src.Pos(), 13);
        sPosLock.Rollback();
        EXPECT_EQ(src.Pos(), 5);
        src.Pos()++;
    }
    EXPECT_EQ(src.Pos(), 6);

    // Promotion; automatic rollback disabled
    src.Pos() = 5;
    {
        auto sPosLock = src.CreatePosLock();
        src.Pos() += 8;
        EXPECT_EQ(src.Pos(), 13);
        sPosLock.Promote();
    }
    EXPECT_EQ(src.Pos(), 13);
}

TEST_F(CDbcParserTest, SourceContent)
{
    std::string ssSource = "VERSION \"123\"";
    dbc::CDbcSource src(ssSource);

    EXPECT_EQ(ssSource, src.Content());
    EXPECT_EQ(ssSource, src.ContentPtr());
    src.Pos() += 2;
    EXPECT_EQ(ssSource.substr(2), src.ContentPtr());
    EXPECT_EQ('R', src.CurrentChar());
}

TEST_F(CDbcParserTest, SourceLineColumn)
{
    std::string ssSource = R"dbc(VERSION ""


NS_ :
    NS_DESC_
    CM_
    BA_DEF_
    BA_
    VAL_
    CAT_DEF_
    CAT_
    FILTER
    BA_DEF_DEF_
    EV_DATA_)dbc";

    dbc::CDbcSource src(ssSource);
    EXPECT_EQ(src.CalcLine(), 1);
    EXPECT_EQ(src.CalcColumn(), 1);
    src.Pos() += 30;
    EXPECT_EQ(src.CalcLine(), 5);
    EXPECT_EQ(src.CalcColumn(), 12);
    src.Pos() += 99999;
    EXPECT_EQ(src.CalcLine(), 14);
    EXPECT_EQ(src.CalcColumn(), 13);

    std::string ssTabs = "\t\na\t\nabcd\t\nabcde\td\t";
    dbc::CDbcSource srcTabs(ssTabs);
    EXPECT_EQ(srcTabs.CalcLine(), 1);
    EXPECT_EQ(srcTabs.CalcColumn(), 1);
    srcTabs.Pos()++;
    EXPECT_EQ(srcTabs.CalcLine(), 1);
    EXPECT_EQ(srcTabs.CalcColumn(), 5);
    srcTabs.Pos()++;
    EXPECT_EQ(srcTabs.CalcLine(), 2);
    EXPECT_EQ(srcTabs.CalcColumn(), 1);
    srcTabs.Pos() += 2;
    EXPECT_EQ(srcTabs.CalcLine(), 2);
    EXPECT_EQ(srcTabs.CalcColumn(), 5);
    srcTabs.Pos() += 6;
    EXPECT_EQ(srcTabs.CalcLine(), 3);
    EXPECT_EQ(srcTabs.CalcColumn(), 9);
    srcTabs.Pos() += 7;
    EXPECT_EQ(srcTabs.CalcLine(), 4);
    EXPECT_EQ(srcTabs.CalcColumn(), 9);
    srcTabs.Pos() += 2;
    EXPECT_EQ(srcTabs.CalcLine(), 4);
    EXPECT_EQ(srcTabs.CalcColumn(), 13);
    srcTabs.Pos()++;
    EXPECT_EQ(srcTabs.CalcLine(), 4);
    EXPECT_EQ(srcTabs.CalcColumn(), 13);
}

TEST_F(CDbcParserTest, ExceptionStructTest)
{
    dbc::SDbcParserException sExceptReason("This is an exception");
    EXPECT_STREQ(sExceptReason.what(), "This is an exception");

    dbc::SDbcParserException sExceptParamMiddle("This is %1 exception", "an");
    EXPECT_STREQ(sExceptParamMiddle.what(), "This is an exception");
    dbc::SDbcParserException sExceptParamMiddleNumber("This is %1 exception", 1);
    EXPECT_STREQ(sExceptParamMiddleNumber.what(), "This is 1 exception");
    int i = 1;
    dbc::SDbcParserException sExceptParamMiddleNumber2("This is %1 exception", i);
    EXPECT_STREQ(sExceptParamMiddleNumber2.what(), "This is 1 exception");

    dbc::SDbcParserException sExceptParamBegin("%1 is an exception", "This");
    EXPECT_STREQ(sExceptParamBegin.what(), "This is an exception");

    dbc::SDbcParserException sExceptParamEnd("This is an %1", "exception");
    EXPECT_STREQ(sExceptParamEnd.what(), "This is an exception");

    dbc::SDbcParserException sExceptParamMultiple("%1 %2 %3 %4", "This", "is", "an", "exception");
    EXPECT_STREQ(sExceptParamMultiple.what(), "This is an exception");
    dbc::SDbcParserException sExceptParamMultipleMixed("%3 %4 %1 %2", "an", "exception", "This", "is");
    EXPECT_STREQ(sExceptParamMultipleMixed.what(), "This is an exception");
    dbc::SDbcParserException sExceptParamMultipleUnused("This is %3 exception", "This", "is", "an", "exception");
    EXPECT_STREQ(sExceptParamMultipleUnused.what(), "This is an exception");

    dbc::SDbcParserException sExceptParamNoEscape("This is an %% exception");
    EXPECT_STREQ(sExceptParamNoEscape.what(), "This is an %% exception");

    dbc::SDbcParserException sExceptParamEscape("This is an %% %1", "exception");
    EXPECT_STREQ(sExceptParamEscape.what(), "This is an % exception");

    dbc::SDbcParserException sExceptParamInvalidIndex("%0 This %2 is an %1 %999", "exception");
    EXPECT_STREQ(sExceptParamInvalidIndex.what(), "<unknown> This <unknown> is an exception <unknown>");
}

TEST_F(CDbcParserTest, ExceptionStructTestWithSource)
{
    std::string ssSource = "\nVERSION \"123\"\n";
    dbc::CDbcSource src(ssSource);
    src.Pos() += 9;
    EXPECT_EQ(src.CalcLine(), 2);
    EXPECT_EQ(src.CalcColumn(), 9);

    dbc::SDbcParserException sExceptReason(src, "This is an exception");
    EXPECT_STREQ(sExceptReason.what(), "[2, 9]: This is an exception");

    dbc::SDbcParserException sExceptParamMiddle(src, "This is %1 exception", "an");
    EXPECT_STREQ(sExceptParamMiddle.what(), "[2, 9]: This is an exception");
    dbc::SDbcParserException sExceptParamMiddleNumber(src, "This is %1 exception", 1);
    EXPECT_STREQ(sExceptParamMiddleNumber.what(), "[2, 9]: This is 1 exception");
    int i = 1;
    dbc::SDbcParserException sExceptParamMiddleNumber2(src, "This is %1 exception", i);
    EXPECT_STREQ(sExceptParamMiddleNumber2.what(), "[2, 9]: This is 1 exception");

    dbc::SDbcParserException sExceptParamBegin(src, "%1 is an exception", "This");
    EXPECT_STREQ(sExceptParamBegin.what(), "[2, 9]: This is an exception");

    dbc::SDbcParserException sExceptParamEnd(src, "This is an %1", "exception");
    EXPECT_STREQ(sExceptParamEnd.what(), "[2, 9]: This is an exception");

    dbc::SDbcParserException sExceptParamMultiple(src, "%1 %2 %3 %4", "This", "is", "an", "exception");
    EXPECT_STREQ(sExceptParamMultiple.what(), "[2, 9]: This is an exception");
    dbc::SDbcParserException sExceptParamMultipleMixed(src, "%3 %4 %1 %2", "an", "exception", "This", "is");
    EXPECT_STREQ(sExceptParamMultipleMixed.what(), "[2, 9]: This is an exception");
    dbc::SDbcParserException sExceptParamMultipleUnused(src, "This is %3 exception", "This", "is", "an", "exception");
    EXPECT_STREQ(sExceptParamMultipleUnused.what(), "[2, 9]: This is an exception");

    dbc::SDbcParserException sExceptParamNoEscape(src, "This is an %% exception");
    EXPECT_STREQ(sExceptParamNoEscape.what(), "[2, 9]: This is an %% exception");

    dbc::SDbcParserException sExceptParamEscape(src, "This is an %% %1", "exception");
    EXPECT_STREQ(sExceptParamEscape.what(), "[2, 9]: This is an % exception");

    dbc::SDbcParserException sExceptParamInvalidIndex(src, "%0 This %2 is an %1 %999", "exception");
    EXPECT_STREQ(sExceptParamInvalidIndex.what(), "[2, 9]: <unknown> This <unknown> is an exception <unknown>");

    dbc::SDbcParserException sExceptReasonStablePosition(src, "This is an exception");
    src.Pos() += 999;
    EXPECT_EQ(src.CalcLine(), 3);
    EXPECT_EQ(src.CalcColumn(), 1);
    EXPECT_EQ(sExceptReasonStablePosition.Source().CalcLine(), 2);
    EXPECT_EQ(sExceptReasonStablePosition.Source().CalcColumn(), 9);

    src.Pos() = 9;
    dbc::SDbcParserException sExceptParamMiddleStablePosition(src, "This is %1 exception", "an");
    src.Pos() += 999;
    EXPECT_EQ(src.CalcLine(), 3);
    EXPECT_EQ(src.CalcColumn(), 1);
    EXPECT_EQ(sExceptParamMiddleStablePosition.Source().CalcLine(), 2);
    EXPECT_EQ(sExceptParamMiddleStablePosition.Source().CalcColumn(), 9);
}

TEST_F(CDbcParserTest, Instantiation)
{
    EXPECT_NO_THROW(dbc::CDbcParser());
}

TEST_F(CDbcParserTest, Version)
{
    std::string ssVersion1 = "VERSION \"123\"";
    dbc::CDbcSource srcVersion1(ssVersion1);
    std::string ssVersion2 = "VERSION \"\"";
    dbc::CDbcSource srcVersion2(ssVersion2);
    std::string ssVersion3 = "\n  VERSION \"123\"\n";
    dbc::CDbcSource srcVersion3(ssVersion3);
    std::string ssMaliciousVersion = "VERSION 123\n";
    dbc::CDbcSource srcMaliciousVersion(ssMaliciousVersion);

    dbc::CDbcParser parser1;
    EXPECT_NO_THROW(parser1.Parse(srcVersion1));
    EXPECT_EQ(parser1.GetVersions(), std::vector<std::string>({ "123" }));

    dbc::CDbcParser parser2;
    EXPECT_NO_THROW(parser2.Parse(srcVersion2));
    EXPECT_EQ(parser2.GetVersions(), std::vector<std::string>({ "" }));

    dbc::CDbcParser parser3;
    EXPECT_NO_THROW(parser3.Parse(srcVersion3));
    EXPECT_EQ(parser3.GetVersions(), std::vector<std::string>({ "123" }));

    dbc::CDbcParser parserMaliciousVersion;
    EXPECT_THROW(parserMaliciousVersion.Parse(srcMaliciousVersion), dbc::SDbcParserException);
    EXPECT_EQ(parserMaliciousVersion.GetVersions(), std::vector<std::string>());

    dbc::CDbcParser parserMulti;
    srcVersion1.ResetPos();
    srcVersion2.ResetPos();
    srcVersion3.ResetPos();
    EXPECT_NO_THROW(parserMulti.Parse(srcVersion1));
    EXPECT_NO_THROW(parserMulti.Parse(srcVersion2));
    EXPECT_NO_THROW(parserMulti.Parse(srcVersion3));
    EXPECT_EQ(parserMulti.GetVersions(), std::vector<std::string>({ "123", "", "123" }));
}

TEST_F(CDbcParserTest, Comments)
{
    // NOTE: Comments are not part of the official standard.
    std::string ssComment1 = "// test 123";
    dbc::CDbcSource srcComment1(ssComment1);
    dbc::CDbcParser parser;
    EXPECT_NO_THROW(parser.Parse(srcComment1));
    std::string ssComment2 = "VERSION \"\" // test 123";
    dbc::CDbcSource srcComment2(ssComment2);
    EXPECT_NO_THROW(parser.Parse(srcComment2));
}

TEST_F(CDbcParserTest, NewSymbols)
{
    dbc::CDbcParser parser;

    // No symbols.
    std::string ssEmptyNS = "NS_:";
    dbc::CDbcSource srcEmptyNS(ssEmptyNS);
    EXPECT_NO_THROW(parser.Parse(srcEmptyNS));

    // One Symbol
    std::string ssOneNS = "NS_: VAL_TABLE_";
    dbc::CDbcSource srcOneNS(ssOneNS);
    EXPECT_NO_THROW(parser.Parse(srcOneNS));

    // All symbols
    std::string ssAllNS = R"dbc(NS_ : NS_DESC_ CM_ BA_DEF_ BA_ VAL_ CAT_DEF_ CAT_ FILTER BA_DEF_DEF_ EV_DATA_
        ENVVAR_DATA_ SGTYPE_ SGTYPE_VAL_ BA_DEF_SGTYPE_ BA_SGTYPE_ SIG_TYPE_REF_ VAL_TABLE_ SIG_GROUP_
        SIG_VALTYPE_ SIGTYPE_VALTYPE_ BO_TX_BU_ BA_DEF_REL_ BA_REL_ BA_DEF_DEF_REL_ BU_SG_REL_
        BU_EV_REL_ BU_BO_REL_ SG_MUL_VAL_)dbc";
    dbc::CDbcSource srcAllNS(ssAllNS);
    EXPECT_NO_THROW(parser.Parse(srcAllNS));

    // Duplicate symbols
    std::string ssDuplicateNS = "NS_: VAL_TABLE_ VAL_TABLE_";
    dbc::CDbcSource srcDuplicateNS(ssDuplicateNS);
    EXPECT_NO_THROW(parser.Parse(srcDuplicateNS));

    // Invalid symbols
    std::string ssInvalidNS = "NS_: INVALID_";
    dbc::CDbcSource srcInvalidNS(ssInvalidNS);
    EXPECT_THROW(parser.Parse(srcInvalidNS), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, BitTiming)
{
    dbc::CDbcParser parser;

    // Valid bit timing
    std::string ssValidBitTiming = "BS_: 500000 : 4, 3";
    dbc::CDbcSource srcValidBitTiming(ssValidBitTiming);
    EXPECT_NO_THROW(parser.Parse(srcValidBitTiming));

    // No bit timing
    std::string ssNoBitTiming = "BS_:";
    dbc::CDbcSource srcNoBitTiming(ssNoBitTiming);
    EXPECT_NO_THROW(parser.Parse(srcNoBitTiming));

    // Invalid bit timing
    std::string ssInvalidBitTiming1 = "BS_: 500000 : 4";
    std::string ssInvalidBitTiming2 = "BS_: 500000 : ";
    std::string ssInvalidBitTiming3 = "BS_: 500000";
    std::string ssInvalidBitTiming4 = "BS_: 4, 3";
    std::string ssInvalidBitTiming5 = "BS_: 500000 : a, b";
    dbc::CDbcSource srcInvalidBitTiming1(ssInvalidBitTiming1);
    dbc::CDbcSource srcInvalidBitTiming2(ssInvalidBitTiming2);
    dbc::CDbcSource srcInvalidBitTiming3(ssInvalidBitTiming3);
    dbc::CDbcSource srcInvalidBitTiming4(ssInvalidBitTiming4);
    dbc::CDbcSource srcInvalidBitTiming5(ssInvalidBitTiming5);
    EXPECT_THROW(parser.Parse(srcInvalidBitTiming1), dbc::SDbcParserException);
    EXPECT_THROW(parser.Parse(srcInvalidBitTiming2), dbc::SDbcParserException);
    EXPECT_THROW(parser.Parse(srcInvalidBitTiming3), dbc::SDbcParserException);
    EXPECT_THROW(parser.Parse(srcInvalidBitTiming4), dbc::SDbcParserException);
    EXPECT_THROW(parser.Parse(srcInvalidBitTiming5), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, NodeDef)
{
    dbc::CDbcParser parser;

    // Valid node def
    std::string ssValidNodeDef = "BU_: MAB SAS RASM BBM";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("MAB"));
    EXPECT_TRUE(parser.HasNodeDef("SAS"));
    EXPECT_TRUE(parser.HasNodeDef("RASM"));
    EXPECT_TRUE(parser.HasNodeDef("BBM"));
    EXPECT_FALSE(parser.HasNodeDef("MSRB"));
    auto vecNodes = parser.GetNodeDefNames();
    EXPECT_EQ(vecNodes.size(), 4);
    EXPECT_NE(std::find(vecNodes.begin(), vecNodes.end(), "MAB"), vecNodes.end());
    EXPECT_NE(std::find(vecNodes.begin(), vecNodes.end(), "SAS"), vecNodes.end());
    EXPECT_NE(std::find(vecNodes.begin(), vecNodes.end(), "RASM"), vecNodes.end());
    EXPECT_NE(std::find(vecNodes.begin(), vecNodes.end(), "BBM"), vecNodes.end());

    // Duplicate node def (in one call, invliad, in separate calls valid).
    std::string ssDuplicateNodeDef1 = "BU_: XYZ SAS";
    dbc::CDbcSource srcDuplicateNodeDef1(ssDuplicateNodeDef1);
    EXPECT_NO_THROW(parser.Parse(srcDuplicateNodeDef1));
    EXPECT_TRUE(parser.HasNodeDef("XYZ"));
    std::string ssDuplicateNodeDef2 = "BU_: ABC DEF ABC";
    dbc::CDbcSource srcDuplicateNodeDef2(ssDuplicateNodeDef2);
    EXPECT_THROW(parser.Parse(srcDuplicateNodeDef2), dbc::SDbcParserException);
    EXPECT_FALSE(parser.HasNodeDef("ABC"));
    EXPECT_FALSE(parser.HasNodeDef("DEF"));

    // No node def
    std::string ssNoNodeDef = "BU_:";
    dbc::CDbcSource srcNoNodeDef(ssNoNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcNoNodeDef));

    // Invalid node defs
    std::string ssInvalidNodeDef1 = "BU_: 123";
    dbc::CDbcSource srcInvalidNodeDef1(ssInvalidNodeDef1);
    EXPECT_THROW(parser.Parse(srcInvalidNodeDef1), dbc::SDbcParserException);
    std::string ssInvalidNodeDef2 = "BU_: BS_";
    dbc::CDbcSource srcInvalidNodeDef2(ssInvalidNodeDef2);
    EXPECT_THROW(parser.Parse(srcInvalidNodeDef2), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, ValueTable)
{
    dbc::CDbcParser parser;

    // Value table
    std::string ssValidValueTable1 = "VAL_TABLE_ table1 10 \"ten\" 20 \"twenty\";";
    dbc::CDbcSource srcValidValueTable1(ssValidValueTable1);
    EXPECT_NO_THROW(parser.Parse(srcValidValueTable1));
    EXPECT_TRUE(parser.HasValueTable("table1"));
    EXPECT_TRUE(parser.HasValue("table1", 10));
    EXPECT_TRUE(parser.HasValue("table1", 20));
    EXPECT_EQ(parser.GetValue("table1", 10), "ten");
    EXPECT_EQ(parser.GetValue("table1", 20), "twenty");
    std::string ssValidValueTable2 = "VAL_TABLE_ table2 20 \"twenty\" 30 \"thirty\";"; // Redefinition of value names allowed
    dbc::CDbcSource srcValidValueTable2(ssValidValueTable2);
    EXPECT_NO_THROW(parser.Parse(srcValidValueTable2));
    auto vecTables = parser.GetValueTableNames();
    ASSERT_EQ(vecTables.size(), 2);
    EXPECT_EQ(vecTables[0], "table1");
    EXPECT_EQ(vecTables[1], "table2");
    auto prEntries = parser.GetValues("table1");
    EXPECT_TRUE(prEntries.second);
    ASSERT_EQ(prEntries.first.size(), 2);
    EXPECT_EQ(prEntries.first[0], 10u);
    EXPECT_EQ(prEntries.first[1], 20u);
    prEntries = parser.GetValues("table2");
    EXPECT_TRUE(prEntries.second);
    ASSERT_EQ(prEntries.first.size(), 2);
    EXPECT_EQ(prEntries.first[0], 20u);
    EXPECT_EQ(prEntries.first[1], 30u);

    // Empty table
    std::string ssEmptyValueTable = "VAL_TABLE_ empty;";
    dbc::CDbcSource srcEmptyValueTable(ssEmptyValueTable);
    EXPECT_NO_THROW(parser.Parse(srcEmptyValueTable));
    EXPECT_TRUE(parser.HasValueTable("empty"));

    // Invalid table
    std::string ssNoValueTable = "VAL_TABLE_;";
    dbc::CDbcSource srcNoValueTable(ssNoValueTable);
    EXPECT_THROW(parser.Parse(srcNoValueTable), dbc::SDbcParserException);
    std::string ssDuplicateValueTable1 = "VAL_TABLE_ table1;"; // Redefinition of "table1"
    dbc::CDbcSource srcDuplicateValueTable1(ssDuplicateValueTable1);
    EXPECT_THROW(parser.Parse(srcDuplicateValueTable1), dbc::SDbcParserException);
    std::string ssDuplicateValueTable2 = "VAL_TABLE_ duplicate_val_table 10 \"ten\" 20 \"twenty\" 10 \"ten\";"; // Duplicate values
    dbc::CDbcSource srcDuplicateValueTable2(ssDuplicateValueTable2);
    EXPECT_THROW(parser.Parse(srcDuplicateValueTable2), dbc::SDbcParserException);
    std::string ssInvalidValueTable1 = "VAL_TABLE_ invalid_table \"ten\" 10 \"twenty\" 20;";   // Wrong order of values
    dbc::CDbcSource srcInvalidValueTable1(ssInvalidValueTable1);
    EXPECT_THROW(parser.Parse(srcInvalidValueTable1), dbc::SDbcParserException);
    std::string ssInvalidValueTable2 = "VAL_TABLE_ invalid_table 10 \"ten\" 20 \"twenty\"";    // Semi-colon missing
    dbc::CDbcSource srcInvalidValueTable2(ssInvalidValueTable2);
    EXPECT_THROW(parser.Parse(srcInvalidValueTable2), dbc::SDbcParserException);
    std::string ssDuplicateValueTable3 = "VAL_TABLE_: table3;"; // Invalid colon
    dbc::CDbcSource srcDuplicateValueTable3(ssDuplicateValueTable3);
    EXPECT_THROW(parser.Parse(srcDuplicateValueTable3), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, MessageDef)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));

    // Message definition
    std::string ssValidMsgDefStdId = "BO_ 1 msg1: 8 nodeTx";
    dbc::CDbcSource srcValidMsgDefStdId(ssValidMsgDefStdId);
    EXPECT_NO_THROW(parser.Parse(srcValidMsgDefStdId));
    EXPECT_TRUE(parser.HasMsgDef("msg1"));
    EXPECT_TRUE(parser.HasMsgDefStdId(1u));
    EXPECT_FALSE(parser.HasMsgDefExtId(1u));
    EXPECT_TRUE(parser.HasMsgDef(1u));
    auto prMsgDef = parser.GetMsgDef("msg1");
    EXPECT_TRUE(prMsgDef.second);
    EXPECT_EQ(prMsgDef.first.ssName, "msg1");
    prMsgDef = parser.GetMsgDef(1u);
    EXPECT_TRUE(prMsgDef.second);
    EXPECT_EQ(prMsgDef.first.ssName, "msg1");
    prMsgDef = parser.GetMsgDefStdId(1u);
    EXPECT_TRUE(prMsgDef.second);
    EXPECT_EQ(prMsgDef.first.ssName, "msg1");
    prMsgDef = parser.GetMsgDefExtId(1u);
    EXPECT_FALSE(prMsgDef.second);
    EXPECT_TRUE(prMsgDef.first.ssName.empty());
    std::string ssValidMsgDefExtId = "BO_ 2147483650 msg2: 8 nodeTx";
    dbc::CDbcSource srcValidMsgDefExtId(ssValidMsgDefExtId);
    EXPECT_NO_THROW(parser.Parse(srcValidMsgDefExtId));
    EXPECT_TRUE(parser.HasMsgDef("msg2"));
    EXPECT_FALSE(parser.HasMsgDefStdId(2));
    EXPECT_TRUE(parser.HasMsgDefExtId(2));
    EXPECT_TRUE(parser.HasMsgDef(2u | 0x80000000u));
    prMsgDef = parser.GetMsgDef("msg2");
    EXPECT_TRUE(prMsgDef.second);
    EXPECT_EQ(prMsgDef.first.ssName, "msg2");
    prMsgDef = parser.GetMsgDef(2u | 0x80000000u);
    EXPECT_TRUE(prMsgDef.second);
    EXPECT_EQ(prMsgDef.first.ssName, "msg2");
    prMsgDef = parser.GetMsgDefStdId(2u);
    EXPECT_FALSE(prMsgDef.second);
    EXPECT_TRUE(prMsgDef.first.ssName.empty());
    prMsgDef = parser.GetMsgDefExtId(2u);
    EXPECT_TRUE(prMsgDef.second);
    EXPECT_EQ(prMsgDef.first.ssName, "msg2");
    auto vecMessagIDs = parser.GetMessageIDs();
    ASSERT_EQ(vecMessagIDs.size(), 2);
    EXPECT_EQ(vecMessagIDs[0], 1u);
    EXPECT_EQ(vecMessagIDs[1], 2u | 0x80000000u);

    // Default node
    std::string ssDefaultNode = "BO_ 3 msg3: 8 Vector__XXX";
    dbc::CDbcSource srcDefaultNode(ssDefaultNode);
    EXPECT_NO_THROW(parser.Parse(srcDefaultNode));
    EXPECT_TRUE(parser.HasMsgDef("msg3"));
    EXPECT_TRUE(parser.HasMsgDefStdId(3));
    EXPECT_FALSE(parser.HasMsgDefExtId(3));

    // Default message
    std::string ssDefaultMsg = "BO_ 1 VECTOR__INDEPENDENT_SIG_MSG: 8 nodeTx BO_ 2 VECTOR__INDEPENDENT_SIG_MSG: 8 Vector__XXX";
    dbc::CDbcSource srcDefaultMsg(ssDefaultMsg);
    EXPECT_NO_THROW(parser.Parse(srcDefaultMsg));
    EXPECT_TRUE(parser.HasMsgDef("VECTOR__INDEPENDENT_SIG_MSG"));

    // Invalid message
    std::string ssDuplicateMsg = "BO_ 1 msg1: 7 nodeTx";    // Duplicate through name; defined before already
    dbc::CDbcSource srcDuplicateMsg(ssDuplicateMsg);
    EXPECT_THROW(parser.Parse(srcDuplicateMsg), dbc::SDbcParserException);
    std::string ssDuplicateMsgId = "BO_ 1 msg11: 8 nodeTx"; // Duplicate through Id.
    dbc::CDbcSource srcDuplicateMsgId(ssDuplicateMsgId);
    EXPECT_THROW(parser.Parse(srcDuplicateMsgId), dbc::SDbcParserException);
    std::string ssInvalidMsg1 = "BO_ 123 msg123: 8";    // Missing transmitter node
    dbc::CDbcSource srcInvalidMsg1(ssInvalidMsg1);
    EXPECT_THROW(parser.Parse(srcInvalidMsg1), dbc::SDbcParserException);
    std::string ssInvalidMsg2 = "BO_ 123 msg123: nodeTx";    // Missing message size
    dbc::CDbcSource srcInvalidMsg2(ssInvalidMsg2);
    EXPECT_THROW(parser.Parse(srcInvalidMsg2), dbc::SDbcParserException);
    std::string ssInvalidMsg3 = "BO_ 123 msg123 8 nodeTx";    // Missing colon
    dbc::CDbcSource srcInvalidMsg3(ssInvalidMsg3);
    EXPECT_THROW(parser.Parse(srcInvalidMsg3), dbc::SDbcParserException);
    std::string ssInvalidMsg4 = "BO_ 123 : 8 nodeTx";    // Missing name
    dbc::CDbcSource srcInvalidMsg4(ssInvalidMsg4);
    EXPECT_THROW(parser.Parse(srcInvalidMsg4), dbc::SDbcParserException);
    std::string ssInvalidMsg5 = "BO_ msg123: 8 nodeTx";    // Missing ID
    dbc::CDbcSource srcInvalidMsg5(ssInvalidMsg5);
    EXPECT_THROW(parser.Parse(srcInvalidMsg5), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, SignalDef)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx1 nodeRx2";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx1"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx2"));

    // Message definition
    std::string ssValidMsgDef1 = R"dbc(
        BO_ 1 msg_big_endian: 8 nodeTx
            SG_ sig1 : 7|4@0+ (1,0) [0|8191] "Nm" nodeRx1
            SG_ sig2 : 3|8@0+ (1,0) [0|8191] "Nm" nodeRx1, nodeRx2
            SG_ sig3 : 11|6@0+ (1,0) [0|8191] "Nm" Vector__XXX
            SG_ sig4 : 21|6@0+ (1,0) [0|8191] "Nm" Vector__XXX
            SG_ sig5 : 31|8@0+ (1,0) [0|8191] "Nm" Vector__XXX
            SG_ sig6 : 39|32@0+ (1,0) [0|8191] "Nm" Vector__XXX
        BO_ 2 msg_little_endian: 8 nodeTx
            SG_ sig1 : 0|4@1+ (1,0) [0|8191] "Nm" nodeRx1
            SG_ sig2 : 4|8@1+ (1,0) [0|8191] "Nm" nodeRx1, nodeRx2
            SG_ sig3 : 12|6@1+ (1,0) [0|8191] "Nm" Vector__XXX
            SG_ sig4 : 18|6@1+ (1,0) [0|8191] "Nm" Vector__XXX
            SG_ sig5 : 24|8@1+ (1,0) [0|8191] "Nm" Vector__XXX
            SG_ sig6 : 32|32@1+ (1,0) [0|8191] "Nm" Vector__XXX
        BO_ 2147483651 msg_multiplexer: 8 nodeTx
            SG_ sig1 M : 0|4@1+ (1,0) [0|0] "" nodeRx1
            SG_ sig2a m 1: 4|8@1+ (1,0) [0|8191] "Nm" nodeRx1, nodeRx2
            SG_ sig3a m 1: 12|6@1+ (1,0) [0|8191] "Nm" Vector__XXX
            SG_ sig4a m 1: 18|6@1+ (1,0) [0|8191] "Nm" Vector__XXX
            SG_ sig5a m 1: 24|8@1+ (1,0) [0|8191] "Nm" Vector__XXX
            SG_ sig2b m 0: 4|32@1+ (1,0) [0|8191] "Nm" nodeRx1, nodeRx2
            SG_ sig6 : 32|32@1+ (1,0) [0|8191] "Nm" Vector__XXX
)dbc";
    dbc::CDbcSource srcValidMsgDef1(ssValidMsgDef1);
    EXPECT_NO_THROW(parser.Parse(srcValidMsgDef1));
    EXPECT_TRUE(parser.HasSignalDef("msg_big_endian", "sig1"));
    EXPECT_TRUE(parser.HasSignalDef("msg_big_endian", "sig2"));
    EXPECT_TRUE(parser.HasSignalDef("msg_big_endian", "sig3"));
    EXPECT_TRUE(parser.HasSignalDef("msg_big_endian", "sig4"));
    EXPECT_TRUE(parser.HasSignalDef("msg_big_endian", "sig5"));
    EXPECT_TRUE(parser.HasSignalDef("msg_big_endian", "sig6"));
    EXPECT_TRUE(parser.HasSignalDef("msg_little_endian", "sig1"));
    EXPECT_TRUE(parser.HasSignalDef("msg_little_endian", "sig2"));
    EXPECT_TRUE(parser.HasSignalDef("msg_little_endian", "sig3"));
    EXPECT_TRUE(parser.HasSignalDef("msg_little_endian", "sig4"));
    EXPECT_TRUE(parser.HasSignalDef("msg_little_endian", "sig5"));
    EXPECT_TRUE(parser.HasSignalDef("msg_little_endian", "sig6"));
    EXPECT_TRUE(parser.HasSignalDef("msg_multiplexer", "sig1"));
    EXPECT_TRUE(parser.HasSignalDef("msg_multiplexer", "sig2a"));
    EXPECT_TRUE(parser.HasSignalDef("msg_multiplexer", "sig3a"));
    EXPECT_TRUE(parser.HasSignalDef("msg_multiplexer", "sig4a"));
    EXPECT_TRUE(parser.HasSignalDef("msg_multiplexer", "sig5a"));
    EXPECT_TRUE(parser.HasSignalDef("msg_multiplexer", "sig2b"));
    EXPECT_TRUE(parser.HasSignalDef("msg_multiplexer", "sig6"));
    EXPECT_TRUE(parser.HasSignalDef(1, "sig1"));
    EXPECT_TRUE(parser.HasSignalDef(1, "sig6"));
    EXPECT_TRUE(parser.HasSignalDef(2, "sig1"));
    EXPECT_TRUE(parser.HasSignalDef(2, "sig6"));
    EXPECT_TRUE(parser.HasSignalDef(2147483651, "sig1"));
    EXPECT_TRUE(parser.HasSignalDef(2147483651, "sig6"));
    EXPECT_TRUE(parser.HasSignalDefStdId(1, "sig1"));
    EXPECT_TRUE(parser.HasSignalDefStdId(1, "sig6"));
    EXPECT_TRUE(parser.HasSignalDefStdId(2, "sig1"));
    EXPECT_TRUE(parser.HasSignalDefStdId(2, "sig6"));
    EXPECT_FALSE(parser.HasSignalDefStdId(3, "sig1"));
    EXPECT_FALSE(parser.HasSignalDefStdId(3, "sig6"));
    EXPECT_FALSE(parser.HasSignalDefExtId(1, "sig1"));
    EXPECT_FALSE(parser.HasSignalDefExtId(1, "sig6"));
    EXPECT_FALSE(parser.HasSignalDefExtId(2, "sig1"));
    EXPECT_FALSE(parser.HasSignalDefExtId(2, "sig6"));
    EXPECT_TRUE(parser.HasSignalDefExtId(3, "sig1"));
    EXPECT_TRUE(parser.HasSignalDefExtId(3, "sig6"));
    std::vector<std::string> vecSignals = parser.GetSignalNames(1);
    ASSERT_EQ(vecSignals.size(), 6u);
    EXPECT_EQ(vecSignals[0], "sig1");
    EXPECT_EQ(vecSignals[1], "sig2");
    EXPECT_EQ(vecSignals[2], "sig3");
    EXPECT_EQ(vecSignals[3], "sig4");
    EXPECT_EQ(vecSignals[4], "sig5");
    EXPECT_EQ(vecSignals[5], "sig6");
    EXPECT_TRUE(parser.GetSignalDef("msg_big_endian", "sig1").second);
    EXPECT_TRUE(parser.GetSignalDef("msg_big_endian", "sig6").second);
    EXPECT_TRUE(parser.GetSignalDef("msg_little_endian", "sig1").second);
    EXPECT_TRUE(parser.GetSignalDef("msg_little_endian", "sig6").second);
    EXPECT_TRUE(parser.GetSignalDef("msg_multiplexer", "sig1").second);
    EXPECT_TRUE(parser.GetSignalDef("msg_multiplexer", "sig6").second);
    EXPECT_TRUE(parser.GetSignalDef(1, "sig1").second);
    EXPECT_TRUE(parser.GetSignalDef(1, "sig6").second);
    EXPECT_TRUE(parser.GetSignalDef(2, "sig1").second);
    EXPECT_TRUE(parser.GetSignalDef(2, "sig6").second);
    EXPECT_TRUE(parser.GetSignalDef(2147483651, "sig1").second);
    EXPECT_TRUE(parser.GetSignalDef(2147483651, "sig6").second);
    EXPECT_TRUE(parser.GetSignalDefStdId(1, "sig1").second);
    EXPECT_TRUE(parser.GetSignalDefStdId(1, "sig6").second);
    EXPECT_TRUE(parser.GetSignalDefStdId(2, "sig1").second);
    EXPECT_TRUE(parser.GetSignalDefStdId(2, "sig6").second);
    EXPECT_FALSE(parser.GetSignalDefStdId(3, "sig1").second);
    EXPECT_FALSE(parser.GetSignalDefStdId(3, "sig6").second);
    EXPECT_FALSE(parser.GetSignalDefExtId(1, "sig1").second);
    EXPECT_FALSE(parser.GetSignalDefExtId(1, "sig6").second);
    EXPECT_FALSE(parser.GetSignalDefExtId(2, "sig1").second);
    EXPECT_FALSE(parser.GetSignalDefExtId(2, "sig6").second);
    EXPECT_TRUE(parser.GetSignalDefExtId(3, "sig1").second);
    EXPECT_TRUE(parser.GetSignalDefExtId(3, "sig6").second);

    // Duplicate signals
    std::string ssDuplicateSigDef1 = R"dbc(
        BO_ 4 msg4: 8 nodeTx
            SG_ sig1 : 52|13@0+ (1,0) [0|8191] "Nm" nodeRx1
            SG_ sig2 : 36|13@0+ (1,0) [0|8191] "Nm" nodeRx1, nodeRx2
            SG_ sig1 : 18|13@0+ (1,0) [0|8191] "Nm" Vector__XXX
        )dbc";
    dbc::CDbcSource srcDuplicateSigDef1(ssDuplicateSigDef1);
    EXPECT_THROW(parser.Parse(srcDuplicateSigDef1), dbc::SDbcParserException);

    // Invalid signals
    std::string ssInvalidStartBit = R"dbc(
        BO_ 5 msg5: 8 nodeTx
            SG_ sig1 : 64|13@0+ (1,0) [0|8191] "Nm" nodeRx1
        )dbc";
    dbc::CDbcSource srcInvalidStartBit(ssInvalidStartBit);
    EXPECT_THROW(parser.Parse(srcInvalidStartBit), dbc::SDbcParserException);
    std::string ssInvalidLengthLittleEndian = R"dbc(
        BO_ 6 msg6: 8 nodeTx
            SG_ sig1 : 33|32@1+ (1,0) [0|8191] "Nm" nodeRx1
        )dbc";
    dbc::CDbcSource srcInvalidLengthLittleEndian(ssInvalidLengthLittleEndian);
    EXPECT_THROW(parser.Parse(srcInvalidLengthLittleEndian), dbc::SDbcParserException);
    std::string ssInvalidLengthBigEndian = R"dbc(
        BO_ 7 msg7: 8 nodeTx
            SG_ sig1 : 38|32@0+ (1,0) [0|8191] "Nm" nodeRx1
        )dbc";
    dbc::CDbcSource srcInvalidLengthBigEndian(ssInvalidLengthBigEndian);
    EXPECT_THROW(parser.Parse(srcInvalidLengthBigEndian), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, SignalTypeDef)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Message definition
    std::string ssMsgDef = R"dbc(
        BO_ 1 msg_float: 8 nodeTx
            SG_ sig_float : 0|32@1- (1,0) [0|8191] "Nm" nodeRx
            SG_ sig_int : 32|32@1+ (1,0) [0|8191] "Nm" nodeRx
        BO_ 2 msg_double: 8 nodeTx
            SG_ sig_double : 0|64@1- (1,0) [0|8191] "Nm" nodeRx
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));
    EXPECT_TRUE(parser.HasMsgDef("msg_float"));
    EXPECT_TRUE(parser.HasMsgDef("msg_double"));
    auto prSigFloat = parser.GetSignalDef("msg_float", "sig_float");
    EXPECT_TRUE(prSigFloat.second);
    EXPECT_EQ(prSigFloat.first.eValType, dbc::SSignalDef::EValueType::signed_integer);
    auto prSigInt = parser.GetSignalDef("msg_float", "sig_int");
    EXPECT_TRUE(prSigInt.second);
    EXPECT_EQ(prSigInt.first.eValType, dbc::SSignalDef::EValueType::unsigned_integer);
    auto prSigDouble = parser.GetSignalDef("msg_double", "sig_double");
    EXPECT_TRUE(prSigDouble.second);
    EXPECT_EQ(prSigDouble.first.eValType, dbc::SSignalDef::EValueType::signed_integer);

    // Set the signal value types.
    std::string ssSigValType = R"dbc(
        SIG_VALTYPE_ 1 sig_float 1;
        SIG_VALTYPE_ 1 sig_int 0;
        SIG_VALTYPE_ 2 sig_double 2;
        )dbc";
    dbc::CDbcSource srcSigValType(ssSigValType);
    EXPECT_NO_THROW(parser.Parse(srcSigValType));

    // Test for int, IEEE float and double.
    prSigFloat = parser.GetSignalDef("msg_float", "sig_float");
    EXPECT_TRUE(prSigFloat.second);
    EXPECT_EQ(prSigFloat.first.eValType, dbc::SSignalDef::EValueType::ieee_float);
    prSigInt = parser.GetSignalDef("msg_float", "sig_int");
    EXPECT_TRUE(prSigInt.second);
    EXPECT_EQ(prSigInt.first.eValType, dbc::SSignalDef::EValueType::unsigned_integer);
    prSigDouble = parser.GetSignalDef("msg_double", "sig_double");
    EXPECT_TRUE(prSigDouble.second);
    EXPECT_EQ(prSigDouble.first.eValType, dbc::SSignalDef::EValueType::ieee_double);
}

TEST_F(CDbcParserTest, TransmitterMsgDef)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeTx2 nodeTx3";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx2"));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx3"));

    // Message definition
    std::string ssMsgDef = "BO_ 1 msg1: 8 nodeTx";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));
    auto prMsgDef = parser.GetMsgDef(1);
    EXPECT_TRUE(prMsgDef.second);
    ASSERT_EQ(prMsgDef.first.vecTransmitters.size(), 1);
    EXPECT_EQ(prMsgDef.first.vecTransmitters[0], "nodeTx");

    // Add additional transmitters
    std::string ssMsgTxDef = "BO_TX_BU_ 1: nodeTx2 nodeTx3 Vector__XXX;";
    dbc::CDbcSource srcMsgTxDef(ssMsgTxDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgTxDef));
    prMsgDef = parser.GetMsgDef(1);
    EXPECT_TRUE(prMsgDef.second);
    ASSERT_EQ(prMsgDef.first.vecTransmitters.size(), 4);
    EXPECT_EQ(prMsgDef.first.vecTransmitters[0], "nodeTx");
    EXPECT_EQ(prMsgDef.first.vecTransmitters[1], "nodeTx2");
    EXPECT_EQ(prMsgDef.first.vecTransmitters[2], "nodeTx3");
    EXPECT_EQ(prMsgDef.first.vecTransmitters[3], "Vector__XXX");

    // Empty transmitter definition
    std::string ssMsgTxDefEmpty = "BO_TX_BU_ 1:;";
    dbc::CDbcSource srcMsgTxDefEmpty(ssMsgTxDefEmpty);
    EXPECT_NO_THROW(parser.Parse(srcMsgTxDefEmpty));

    // Invalid transmitter definitions
    std::string ssMsgTxDefDuplicate1 = "BO_TX_BU_ 1: nodeTx2;";
    dbc::CDbcSource srcMsgTxDefDuplicate1(ssMsgTxDefDuplicate1);
    EXPECT_THROW(parser.Parse(srcMsgTxDefDuplicate1), dbc::SDbcParserException);
    std::string ssMsgTxDefDuplicate2 = "BO_TX_BU_ 1: Vector__XXX;";
    dbc::CDbcSource srcMsgTxDefDuplicate2(ssMsgTxDefDuplicate2);
    EXPECT_THROW(parser.Parse(srcMsgTxDefDuplicate2), dbc::SDbcParserException);
    std::string ssMsgTxDefMissingSemiColon = "BO_TX_BU_ 1:";
    dbc::CDbcSource srcMsgTxDefMissingSemiColon(ssMsgTxDefMissingSemiColon);
    EXPECT_THROW(parser.Parse(srcMsgTxDefMissingSemiColon), dbc::SDbcParserException);
    std::string ssMsgTxDefInvalidNode = "BO_TX_BU_ 1: abc;";
    dbc::CDbcSource srcMsgTxDefInvalidNode(ssMsgTxDefInvalidNode);
    EXPECT_THROW(parser.Parse(srcMsgTxDefInvalidNode), dbc::SDbcParserException);
    std::string ssMsgTxDefInvalidMsg = "BO_TX_BU_ 2: ;";
    dbc::CDbcSource srcMsgTxDefInvalidMsg(ssMsgTxDefInvalidMsg);
    EXPECT_THROW(parser.Parse(srcMsgTxDefInvalidMsg), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, SignalValueDescriptions)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Message definition
    std::string ssMsgDef = R"dbc(
        BO_ 1 msg_enum: 8 nodeTx
            SG_ sig_enum : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig_enum_empty : 0|32@1+ (1,0) [0|0] "" nodeRx
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));
    EXPECT_TRUE(parser.HasMsgDef("msg_enum"));
    EXPECT_TRUE(parser.HasSignalDef("msg_enum", "sig_enum"));
    auto prSigEnum = parser.GetSignalDef("msg_enum", "sig_enum");
    EXPECT_TRUE(prSigEnum.second);
    EXPECT_TRUE(prSigEnum.first.mapValueDescriptions.empty());

    // Signal value descriptions
    std::string ssSigValDesc = "VAL_ 1 sig_enum 10 \"ten\" 20 \"twenty\" 30 \"thirty\";";
    dbc::CDbcSource srcSigValDesc(ssSigValDesc);
    EXPECT_NO_THROW(parser.Parse(srcSigValDesc));
    prSigEnum = parser.GetSignalDef("msg_enum", "sig_enum");
    EXPECT_TRUE(prSigEnum.second);
    ASSERT_EQ(prSigEnum.first.mapValueDescriptions.size(), 3);
    EXPECT_EQ(prSigEnum.first.mapValueDescriptions[10], "ten");
    EXPECT_EQ(prSigEnum.first.mapValueDescriptions[20], "twenty");
    EXPECT_EQ(prSigEnum.first.mapValueDescriptions[30], "thirty");

    // Empty signal value description
    std::string ssSigValDescEmpty = "VAL_ 1 sig_enum_empty; ";
    dbc::CDbcSource srcSigValDescEmpty(ssSigValDescEmpty);
    EXPECT_NO_THROW(parser.Parse(srcSigValDescEmpty));
    prSigEnum = parser.GetSignalDef("msg_enum", "sig_enum_empty");
    EXPECT_TRUE(prSigEnum.second);
    EXPECT_TRUE(prSigEnum.first.mapValueDescriptions.empty());

    // Invalid value descriptions
    std::string ssSigValDescDuplicate1 = "VAL_ 1 sig_enum;";
    dbc::CDbcSource srcSigValDescDuplicate1(ssSigValDescDuplicate1);
    EXPECT_THROW(parser.Parse(srcSigValDescDuplicate1), dbc::SDbcParserException);
    std::string ssSigValDescDuplicate2 = "VAL_ 1 sig_enum_empty 10 \"ten\" 20 \"twenty\" 10 \"ten\";";
    dbc::CDbcSource srcSigValDescDuplicate2(ssSigValDescDuplicate2);
    EXPECT_THROW(parser.Parse(srcSigValDescDuplicate2), dbc::SDbcParserException);
    std::string ssSigValDescMissingSemiColon = "VAL_ 1 sig_enum_empty 10 \"ten\"";
    dbc::CDbcSource srcSigValDescMissingSemiColon(ssSigValDescMissingSemiColon);
    EXPECT_THROW(parser.Parse(srcSigValDescMissingSemiColon), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, EnvironmentVariableDef)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Environment variable definition
    std::string ssEnvVarDef = R"dbc(
    EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
    EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
    EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)dbc";
    dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
    EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));
    auto vecEnvVars = parser.GetEnvVarNames();
    ASSERT_EQ(vecEnvVars.size(), 3u);
    EXPECT_EQ(vecEnvVars[0], "var1");
    EXPECT_EQ(vecEnvVars[1], "var2");
    EXPECT_EQ(vecEnvVars[2], "var3");
    auto prEnvVar = parser.GetEnvVarDef("var1");
    EXPECT_TRUE(prEnvVar.second);
    EXPECT_EQ(prEnvVar.first.ssName, "var1");
    EXPECT_EQ(prEnvVar.first.eType, dbc::SEnvVarDef::EType::integer);
    EXPECT_EQ(prEnvVar.first.dMinimum, 10.0);
    EXPECT_EQ(prEnvVar.first.dMaximum, 20.0);
    EXPECT_EQ(prEnvVar.first.ssUnit, "steps");
    EXPECT_EQ(prEnvVar.first.dInitVal, 15.0);
    EXPECT_EQ(prEnvVar.first.uiId, 100u);
    EXPECT_EQ(prEnvVar.first.eAccess, dbc::SEnvVarDef::EAccessType::readwrite);
    ASSERT_EQ(prEnvVar.first.vecNodes.size(), 2);
    EXPECT_EQ(prEnvVar.first.vecNodes[0], "nodeTx");
    EXPECT_EQ(prEnvVar.first.vecNodes[1], "nodeRx");
    prEnvVar = parser.GetEnvVarDef("var2");
    EXPECT_TRUE(prEnvVar.second);
    EXPECT_EQ(prEnvVar.first.ssName, "var2");
    EXPECT_EQ(prEnvVar.first.eType, dbc::SEnvVarDef::EType::floating_point);
    EXPECT_EQ(prEnvVar.first.dMinimum, 0.1);
    EXPECT_EQ(prEnvVar.first.dMaximum, 0.2);
    EXPECT_EQ(prEnvVar.first.ssUnit, "tenth steps");
    EXPECT_EQ(prEnvVar.first.dInitVal, 0.5);
    EXPECT_EQ(prEnvVar.first.uiId, 101u);
    EXPECT_EQ(prEnvVar.first.eAccess, dbc::SEnvVarDef::EAccessType::write);
    ASSERT_EQ(prEnvVar.first.vecNodes.size(), 1);
    EXPECT_EQ(prEnvVar.first.vecNodes[0], "nodeTx");
    prEnvVar = parser.GetEnvVarDef("var3");
    EXPECT_TRUE(prEnvVar.second);
    EXPECT_EQ(prEnvVar.first.ssName, "var3");
    EXPECT_EQ(prEnvVar.first.eType, dbc::SEnvVarDef::EType::string);
    EXPECT_EQ(prEnvVar.first.dMinimum, 0.0);
    EXPECT_EQ(prEnvVar.first.dMaximum, 0.0);
    EXPECT_EQ(prEnvVar.first.ssUnit, "string val");
    EXPECT_EQ(prEnvVar.first.dInitVal, 0.0);
    EXPECT_EQ(prEnvVar.first.uiId, 102u);
    EXPECT_EQ(prEnvVar.first.eAccess, dbc::SEnvVarDef::EAccessType::read);
    ASSERT_EQ(prEnvVar.first.vecNodes.size(), 1);
    EXPECT_EQ(prEnvVar.first.vecNodes[0], "nodeRx");
}

TEST_F(CDbcParserTest, EnvVarData)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Environment variable definition
    std::string ssEnvVarDef = R"dbc(
    EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
    EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
    EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)dbc";
    dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
    EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));

    // Environment variable data definition
    std::string ssEnvVarDataDef = R"dbc(
    ENVVAR_DATA_ var1 : 10;
)dbc";
    dbc::CDbcSource srcEnvVarDataDef(ssEnvVarDataDef);
    EXPECT_NO_THROW(parser.Parse(srcEnvVarDataDef));
    auto prEnvVar = parser.GetEnvVarDef("var1");
    EXPECT_TRUE(prEnvVar.second);
    EXPECT_EQ(prEnvVar.first.ssName, "var1");
    EXPECT_EQ(prEnvVar.first.eType, dbc::SEnvVarDef::EType::data);
    EXPECT_EQ(prEnvVar.first.uiDataSize, 10u);
    EXPECT_EQ(prEnvVar.first.dMinimum, 10.0);
    EXPECT_EQ(prEnvVar.first.dMaximum, 20.0);
    EXPECT_EQ(prEnvVar.first.ssUnit, "steps");
    EXPECT_EQ(prEnvVar.first.dInitVal, 15.0);
    EXPECT_EQ(prEnvVar.first.uiId, 100u);
    EXPECT_EQ(prEnvVar.first.eAccess, dbc::SEnvVarDef::EAccessType::readwrite);
    ASSERT_EQ(prEnvVar.first.vecNodes.size(), 2);
    EXPECT_EQ(prEnvVar.first.vecNodes[0], "nodeTx");
    EXPECT_EQ(prEnvVar.first.vecNodes[1], "nodeRx");
}

TEST_F(CDbcParserTest, EnvVarValueDescriptions)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Environment variable definition
    std::string ssEnvVarDef = R"dbc(
    EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
    EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
    EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)dbc";
    dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
    EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));

    // Signal value descriptions
    std::string ssSigValDesc = "VAL_ var1 10 \"ten\" 20 \"twenty\" 30 \"thirty\";";
    dbc::CDbcSource srcSigValDesc(ssSigValDesc);
    EXPECT_NO_THROW(parser.Parse(srcSigValDesc));
    auto prEnvVar = parser.GetEnvVarDef("var1");
    EXPECT_TRUE(prEnvVar.second);
    ASSERT_EQ(prEnvVar.first.mapValueDescriptions.size(), 3);
    EXPECT_EQ(prEnvVar.first.mapValueDescriptions[10], "ten");
    EXPECT_EQ(prEnvVar.first.mapValueDescriptions[20], "twenty");
    EXPECT_EQ(prEnvVar.first.mapValueDescriptions[30], "thirty");

    // Empty signal value description
    std::string ssSigValDescEmpty = "VAL_ var2; ";
    dbc::CDbcSource srcSigValDescEmpty(ssSigValDescEmpty);
    EXPECT_NO_THROW(parser.Parse(srcSigValDescEmpty));
    prEnvVar = parser.GetEnvVarDef("var2");
    EXPECT_TRUE(prEnvVar.second);
    EXPECT_TRUE(prEnvVar.first.mapValueDescriptions.empty());

    // Invalid value descriptions
    std::string ssEnvVarValDescDuplicate2 = "VAL_ var3 10 \"ten\" 20 \"twenty\" 10 \"ten\";";
    dbc::CDbcSource srcEnvVarValDescDuplicate2(ssEnvVarValDescDuplicate2);
    EXPECT_THROW(parser.Parse(srcEnvVarValDescDuplicate2), dbc::SDbcParserException);
    std::string ssEnvVarValDescMissingSemiColon = "VAL_ var3 10 \"ten\"";
    dbc::CDbcSource srcEnvVarValDescMissingSemiColon(ssEnvVarValDescMissingSemiColon);
    EXPECT_THROW(parser.Parse(srcEnvVarValDescMissingSemiColon), dbc::SDbcParserException);
}

TEST_F(CDbcParserTest, ExtSignalTypeDef)
{
    dbc::CDbcParser parser;

    // Value table
    std::string ssValueTable = R"dbc(
        VAL_TABLE_ table1 10 "ten" 20 "twenty";
)dbc";
    dbc::CDbcSource srcValueTable(ssValueTable);
    EXPECT_NO_THROW(parser.Parse(srcValueTable));

    // Value table type definition
    std::string ssValueTableType = R"dbc(
        SGTYPE_ sgtype1 : 32 @ 1+ (1.0, 0) [0|100] "signal unit" 50, table1;
        SGTYPE_ sgtype2 : 16 @ 0- (-10.5, 10) [-100|200] "signal unit2" 13, Vector__XXX;
)dbc";
    dbc::CDbcSource srcValueTableType(ssValueTableType);
    EXPECT_NO_THROW(parser.Parse(srcValueTableType));
    auto vecSignalTypes = parser.GetSignalTypeDefNames();
    ASSERT_EQ(vecSignalTypes.size(), 2);
    EXPECT_EQ(vecSignalTypes[0], "sgtype1");
    EXPECT_EQ(vecSignalTypes[1], "sgtype2");
    auto prSignalType = parser.GetSignalTypeDef("sgtype1");
    EXPECT_TRUE(prSignalType.second);
    EXPECT_EQ(prSignalType.first.ssName, "sgtype1");
    EXPECT_EQ(prSignalType.first.dDefaultValue, 50.0);
    EXPECT_EQ(prSignalType.first.ssValueTable, "table1");
    EXPECT_EQ(prSignalType.first.uiSize, 32u);
    EXPECT_EQ(prSignalType.first.eByteOrder, dbc::SSignalTypeBase::EByteOrder::little_endian);
    EXPECT_EQ(prSignalType.first.eValType, dbc::SSignalTypeBase::EValueType::unsigned_integer);
    EXPECT_EQ(prSignalType.first.dFactor, 1.0);
    EXPECT_EQ(prSignalType.first.dOffset, 0.0);
    EXPECT_EQ(prSignalType.first.dMinimum, 0.0);
    EXPECT_EQ(prSignalType.first.dMaximum, 100.0);
    EXPECT_EQ(prSignalType.first.ssUnit, "signal unit");
    prSignalType = parser.GetSignalTypeDef("sgtype2");
    EXPECT_TRUE(prSignalType.second);
    EXPECT_EQ(prSignalType.first.ssName, "sgtype2");
    EXPECT_EQ(prSignalType.first.dDefaultValue, 13.0);
    EXPECT_EQ(prSignalType.first.ssValueTable, "Vector__XXX");
    EXPECT_EQ(prSignalType.first.uiSize, 16u);
    EXPECT_EQ(prSignalType.first.eByteOrder, dbc::SSignalTypeBase::EByteOrder::big_endian);
    EXPECT_EQ(prSignalType.first.eValType, dbc::SSignalTypeBase::EValueType::signed_integer);
    EXPECT_EQ(prSignalType.first.dFactor, -10.5);
    EXPECT_EQ(prSignalType.first.dOffset, 10.0);
    EXPECT_EQ(prSignalType.first.dMinimum, -100.0);
    EXPECT_EQ(prSignalType.first.dMaximum, 200.0);
    EXPECT_EQ(prSignalType.first.ssUnit, "signal unit2");
}

TEST_F(CDbcParserTest, SignalTypeRef)
{
    dbc::CDbcParser parser;

    // Value table
    std::string ssValueTable = R"dbc(
        VAL_TABLE_ table1 10 "ten" 20 "twenty";
        VAL_TABLE_ table2 20 "twenty" 30 "thirty";
)dbc";
    dbc::CDbcSource srcValueTable(ssValueTable);
    EXPECT_NO_THROW(parser.Parse(srcValueTable));

    // Signal type definition
    std::string ssSignalType = R"dbc(
        SGTYPE_ sgtype1 : 32 @ 1+ (1.0, 0) [0|100] "signal unit" 50, table1;
)dbc";
    dbc::CDbcSource srcSignalType(ssSignalType);
    EXPECT_NO_THROW(parser.Parse(srcSignalType));

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Message definition
    std::string ssMsgDef = R"dbc(
        BO_ 1 msg: 8 nodeTx
            SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));

    // Signal type reference
    std::string ssSignalTypeRef = "SGTYPE_ 1 sig1 : sgtype1;";
    dbc::CDbcSource srcSignalTypeRef(ssSignalTypeRef);
    EXPECT_NO_THROW(parser.Parse(srcSignalTypeRef));
    auto prSignal = parser.GetSignalDef(1, "sig1");
    ASSERT_TRUE(prSignal.second);
    EXPECT_EQ(prSignal.first.ssSignalTypeDef, "sgtype1");
}

TEST_F(CDbcParserTest, SignalGroupDef)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Message definition
    std::string ssMsgDef = R"dbc(
        BO_ 1 msg: 8 nodeTx
            SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));

    // Signal group definition
    std::string ssSignalGroup = R"dbc(
        SIG_GROUP_ 1 group1 10 : sig1 sig2;
        SIG_GROUP_ 1 group2 20 : sig3;
    )dbc";
    dbc::CDbcSource srcSignalGroup(ssSignalGroup);
    EXPECT_NO_THROW(parser.Parse(srcSignalGroup));
    auto vecGroupNames = parser.GetSignalGroupDefNames(1);
    ASSERT_EQ(vecGroupNames.size(), 2u);
    EXPECT_EQ(vecGroupNames[0], "group1");
    EXPECT_EQ(vecGroupNames[1], "group2");
    auto prGroupDef = parser.GetSignalGroupDef(1, "group1");
    EXPECT_TRUE(prGroupDef.second);
    EXPECT_EQ(prGroupDef.first.ssName, "group1");
    EXPECT_EQ(prGroupDef.first.uiRepetitions, 10u);
    ASSERT_EQ(prGroupDef.first.vecSignals.size(), 2u);
    EXPECT_EQ(prGroupDef.first.vecSignals[0], "sig1");
    EXPECT_EQ(prGroupDef.first.vecSignals[1], "sig2");
    prGroupDef = parser.GetSignalGroupDef(1, "group2");
    EXPECT_TRUE(prGroupDef.second);
    EXPECT_EQ(prGroupDef.first.ssName, "group2");
    EXPECT_EQ(prGroupDef.first.uiRepetitions, 20u);
    ASSERT_EQ(prGroupDef.first.vecSignals.size(), 1u);
    EXPECT_EQ(prGroupDef.first.vecSignals[0], "sig3");
}

TEST_F(CDbcParserTest, GlobalComments)
{
    dbc::CDbcParser parser;

    // Global comments
    std::string ssComments = R"dbc(
        CM_ "first comment";
        CM_ "second comment";
        CM_ "third comment";
        CM_ "fourth comment";
    )dbc";
    dbc::CDbcSource srcComments(ssComments);
    EXPECT_NO_THROW(parser.Parse(srcComments));
    auto vecComments = parser.GetComments();
    ASSERT_EQ(vecComments.size(), 4u);
    EXPECT_EQ(vecComments[0], "first comment");
    EXPECT_EQ(vecComments[1], "second comment");
    EXPECT_EQ(vecComments[2], "third comment");
    EXPECT_EQ(vecComments[3], "fourth comment");
}

TEST_F(CDbcParserTest, NodeComments)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Node comments
    std::string ssComments = R"dbc(
        CM_ BU_ nodeTx "first comment";
        CM_ BU_ nodeTx "second comment \"with quotes\"";
        CM_ BU_ nodeRx "third comment 'with single quotes'";
        CM_ BU_ nodeRx "fourth comment";
    )dbc";
    dbc::CDbcSource srcComments(ssComments);
    EXPECT_NO_THROW(parser.Parse(srcComments));
    auto prNode = parser.GetNodeDef("nodeTx");
    EXPECT_TRUE(prNode.second);
    ASSERT_EQ(prNode.first.vecComments.size(), 2u);
    EXPECT_EQ(prNode.first.vecComments[0], "first comment");
    EXPECT_EQ(prNode.first.vecComments[1], "second comment \"with quotes\"");
    prNode = parser.GetNodeDef("nodeRx");
    EXPECT_TRUE(prNode.second);
    ASSERT_EQ(prNode.first.vecComments.size(), 2u);
    EXPECT_EQ(prNode.first.vecComments[0], "third comment 'with single quotes'");
    EXPECT_EQ(prNode.first.vecComments[1], "fourth comment");
}

TEST_F(CDbcParserTest, MessageComments)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Message definition
    std::string ssMsgDef = R"dbc(
        BO_ 1 msg: 8 nodeTx
            SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));

    // Message comments
    std::string ssComments = R"dbc(
        CM_ BO_ 1 "first comment";
        CM_ BO_ 1 "second comment";
        CM_ BO_ 1 "third comment";
        CM_ BO_ 1 "fourth comment";
    )dbc";
    dbc::CDbcSource srcComments(ssComments);
    EXPECT_NO_THROW(parser.Parse(srcComments));
    auto prMsgDef = parser.GetMsgDef(1);
    EXPECT_TRUE(prMsgDef.second);
    ASSERT_EQ(prMsgDef.first.vecComments.size(), 4u);
    EXPECT_EQ(prMsgDef.first.vecComments[0], "first comment");
    EXPECT_EQ(prMsgDef.first.vecComments[1], "second comment");
    EXPECT_EQ(prMsgDef.first.vecComments[2], "third comment");
    EXPECT_EQ(prMsgDef.first.vecComments[3], "fourth comment");
}

TEST_F(CDbcParserTest, SignalComments)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Signal definition
    std::string ssMsgDef = R"dbc(
        BO_ 1 msg: 8 nodeTx
            SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));

    // Node comments
    std::string ssComments = R"dbc(
        CM_ SG_ 1 sig1 "first comment";
        CM_ SG_ 1 sig1 "second comment";
        CM_ SG_ 1 sig2 "third comment";
        CM_ SG_ 1 sig3 "fourth comment";
    )dbc";
    dbc::CDbcSource srcComments(ssComments);
    EXPECT_NO_THROW(parser.Parse(srcComments));
    auto prSignal = parser.GetSignalDef(1, "sig1");
    EXPECT_TRUE(prSignal.second);
    ASSERT_EQ(prSignal.first.vecComments.size(), 2u);
    EXPECT_EQ(prSignal.first.vecComments[0], "first comment");
    EXPECT_EQ(prSignal.first.vecComments[1], "second comment");
    prSignal = parser.GetSignalDef(1, "sig2");
    EXPECT_TRUE(prSignal.second);
    ASSERT_EQ(prSignal.first.vecComments.size(), 1u);
    EXPECT_EQ(prSignal.first.vecComments[0], "third comment");
    prSignal = parser.GetSignalDef(1, "sig3");
    EXPECT_TRUE(prSignal.second);
    ASSERT_EQ(prSignal.first.vecComments.size(), 1u);
    EXPECT_EQ(prSignal.first.vecComments[0], "fourth comment");
}

TEST_F(CDbcParserTest, EnvVarComments)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Environment variable definition
    std::string ssEnvVarDef = R"dbc(
    EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
    EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
    EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)dbc";
    dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
    EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));

    // Env var comments
    std::string ssComments = R"dbc(
        CM_ EV_ var1 "first comment";
        CM_ EV_ var1 "second comment";
        CM_ EV_ var2 "third comment";
        CM_ EV_ var3 "fourth comment";
    )dbc";
    dbc::CDbcSource srcComments(ssComments);
    EXPECT_NO_THROW(parser.Parse(srcComments));
    auto prEnvVar = parser.GetEnvVarDef("var1");
    EXPECT_TRUE(prEnvVar.second);
    ASSERT_EQ(prEnvVar.first.vecComments.size(), 2u);
    EXPECT_EQ(prEnvVar.first.vecComments[0], "first comment");
    EXPECT_EQ(prEnvVar.first.vecComments[1], "second comment");
    prEnvVar = parser.GetEnvVarDef("var2");
    EXPECT_TRUE(prEnvVar.second);
    ASSERT_EQ(prEnvVar.first.vecComments.size(), 1u);
    EXPECT_EQ(prEnvVar.first.vecComments[0], "third comment");
    prEnvVar = parser.GetEnvVarDef("var3");
    EXPECT_TRUE(prEnvVar.second);
    ASSERT_EQ(prEnvVar.first.vecComments.size(), 1u);
    EXPECT_EQ(prEnvVar.first.vecComments[0], "fourth comment");
}

TEST_F(CDbcParserTest, AttributeDef)
{
    dbc::CDbcParser parser(true);

    // Global attribute definition
    // The use of "n/a" and "not-used" is not part of the official standard.
    std::string ssAttribute = R"dbc(
        BA_DEF_ "attr1" INT 10 20;
        BA_DEF_ "attr2" HEX 10 20;
        BA_DEF_ "attr3" FLOAT 1.0 10.9;
        BA_DEF_ "attr4" STRING;
        BA_DEF_ "attr5" ENUM "abc", "def", "ghi";
        BA_DEF_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
    )dbc";
    dbc::CDbcSource srcAttribute(ssAttribute);
    EXPECT_NO_THROW(parser.Parse(srcAttribute));
    auto vecAttr = parser.GetAttributeDefNames();
    ASSERT_EQ(vecAttr.size(), 6u);
    EXPECT_EQ(vecAttr[0], "attr1");
    EXPECT_EQ(vecAttr[1], "attr2");
    EXPECT_EQ(vecAttr[2], "attr3");
    EXPECT_EQ(vecAttr[3], "attr4");
    EXPECT_EQ(vecAttr[4], "attr5");
    EXPECT_EQ(vecAttr[5], "attr6");
    auto prAttr = parser.GetAttributeDef("attr1");
    EXPECT_TRUE(prAttr.second);
    EXPECT_EQ(prAttr.first.ssName, "attr1");
    EXPECT_EQ(prAttr.first.eType, dbc::SAttributeDef::EType::integer);
    EXPECT_EQ(prAttr.first.sIntValues.iMinimum, 10);
    EXPECT_EQ(prAttr.first.sIntValues.iMaximum, 20);
    prAttr = parser.GetAttributeDef("attr2");
    EXPECT_TRUE(prAttr.second);
    EXPECT_EQ(prAttr.first.ssName, "attr2");
    EXPECT_EQ(prAttr.first.eType, dbc::SAttributeDef::EType::hex_integer);
    EXPECT_EQ(prAttr.first.sHexValues.uiMinimum, 10u);
    EXPECT_EQ(prAttr.first.sHexValues.uiMaximum, 20u);
    prAttr = parser.GetAttributeDef("attr3");
    EXPECT_TRUE(prAttr.second);
    EXPECT_EQ(prAttr.first.ssName, "attr3");
    EXPECT_EQ(prAttr.first.eType, dbc::SAttributeDef::EType::floating_point);
    EXPECT_EQ(prAttr.first.sFltValues.dMinimum, 1.0);
    EXPECT_EQ(prAttr.first.sFltValues.dMaximum, 10.9);
    prAttr = parser.GetAttributeDef("attr4");
    EXPECT_TRUE(prAttr.second);
    EXPECT_EQ(prAttr.first.ssName, "attr4");
    EXPECT_EQ(prAttr.first.eType, dbc::SAttributeDef::EType::string);
    prAttr = parser.GetAttributeDef("attr5");
    EXPECT_TRUE(prAttr.second);
    EXPECT_EQ(prAttr.first.ssName, "attr5");
    EXPECT_EQ(prAttr.first.eType, dbc::SAttributeDef::EType::enumerator);
    ASSERT_EQ(prAttr.first.sEnumValues.vecEnumValues.size(), 3u);
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[0], "abc");
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[1], "def");
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[2], "ghi");
    prAttr = parser.GetAttributeDef("attr6");
    EXPECT_TRUE(prAttr.second);
    EXPECT_EQ(prAttr.first.ssName, "attr6");
    EXPECT_EQ(prAttr.first.eType, dbc::SAttributeDef::EType::enumerator);
    ASSERT_EQ(prAttr.first.sEnumValues.vecEnumValues.size(), 7u);
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[0], "abc");
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[1], "n/a");
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[2], "not-used");
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[3], "jkl");
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[4], "n/a");
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[5], "not-used");
    EXPECT_EQ(prAttr.first.sEnumValues.vecEnumValues[6], "stu");
}

TEST_F(CDbcParserTest, AttributeDefaultValDef)
{
    dbc::CDbcParser parser;

    // Global attribute definition
    // The use of "n/a" and "not-used" is not part of the official standard.
    std::string ssAttribute = R"dbc(
        BA_DEF_ "attr1" INT 10 20;
        BA_DEF_ "attr2" HEX 10 20;
        BA_DEF_ "attr3" FLOAT 1.0 10.9;
        BA_DEF_ "attr4" STRING;
        BA_DEF_ "attr5" ENUM "abc", "def", "ghi";
        BA_DEF_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
    )dbc";
    dbc::CDbcSource srcAttribute(ssAttribute);
    EXPECT_NO_THROW(parser.Parse(srcAttribute));

    // Attribute def default value
    // The use of an index instead of a value for the enum value is not part of the official standard.
    std::string ssAttrDefDefaultVal = R"dbc(
        BA_DEF_DEF_ "attr1" 15;
        BA_DEF_DEF_ "attr2" 15;
        BA_DEF_DEF_ "attr3" 5.5;
        BA_DEF_DEF_ "attr4" "hello";
        BA_DEF_DEF_ "attr5" "def";
        BA_DEF_DEF_ "attr6" 6;
    )dbc";
    dbc::CDbcSource srcAttrDefDefaultVal(ssAttrDefDefaultVal);
    EXPECT_NO_THROW(parser.Parse(srcAttrDefDefaultVal));

    auto prAttr = parser.GetAttributeDef("attr1");
    EXPECT_EQ(prAttr.first.sIntValues.iDefault, 15);
    prAttr = parser.GetAttributeDef("attr2");
    EXPECT_EQ(prAttr.first.sHexValues.uiDefault, 15u);
    prAttr = parser.GetAttributeDef("attr3");
    EXPECT_EQ(prAttr.first.sFltValues.dDefault, 5.5);
    prAttr = parser.GetAttributeDef("attr4");
    EXPECT_EQ(prAttr.first.sStringValues.ssDefault, "hello");
    prAttr = parser.GetAttributeDef("attr5");
    EXPECT_EQ(prAttr.first.sEnumValues.ssDefault, "def");
    prAttr = parser.GetAttributeDef("attr6");
    EXPECT_EQ(prAttr.first.sEnumValues.ssDefault, "stu");
}

TEST_F(CDbcParserTest, GlobalAttributeVal)
{
    dbc::CDbcParser parser;

    // Global attribute definition
    // The use of "n/a" and "not-used" is not part of the official standard.
    std::string ssAttribute = R"dbc(
        BA_DEF_ "attr1" INT 10 20;
        BA_DEF_ "attr2" HEX 10 20;
        BA_DEF_ "attr3" FLOAT 1.0 10.9;
        BA_DEF_ "attr4" STRING;
        BA_DEF_ "attr5" ENUM "abc", "def", "ghi";
        BA_DEF_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
    )dbc";
    dbc::CDbcSource srcAttribute(ssAttribute);
    EXPECT_NO_THROW(parser.Parse(srcAttribute));

    // Attribute value
    // The use of an index instead of a value for the enum value is not part of the official standard.
    std::string ssAttrVal = R"dbc(
        BA_ "attr1" 11;
        BA_ "attr2" 12;
        BA_ "attr2" 13;
        BA_ "attr3" 3.5;
        BA_ "attr4" "hi";
        BA_ "attr5" "ghi";
        BA_ "attr6" 6;
    )dbc";
    dbc::CDbcSource srcAttrVal(ssAttrVal);
    EXPECT_NO_THROW(parser.Parse(srcAttrVal));
    auto vecAttr = parser.GetAttributes();
    ASSERT_EQ(vecAttr.size(), 7u);
    EXPECT_EQ(vecAttr[0].iValue, 11);
    EXPECT_EQ(vecAttr[1].uiValue, 12u);
    EXPECT_EQ(vecAttr[2].uiValue, 13u);
    EXPECT_EQ(vecAttr[3].dValue, 3.5);
    EXPECT_EQ(vecAttr[4].ssValue, "hi");
    EXPECT_EQ(vecAttr[5].ssValue, "ghi");
    EXPECT_EQ(vecAttr[6].ssValue, "stu");
}

TEST_F(CDbcParserTest, NodeAttributeVal)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Node attribute definition
    // The use of "n/a" and "not-used" is not part of the official standard.
    std::string ssAttribute = R"dbc(
        BA_DEF_ BU_ "attr1" INT 10 20;
        BA_DEF_ BU_ "attr2" HEX 10 20;
        BA_DEF_ BU_ "attr3" FLOAT 1.0 10.9;
        BA_DEF_ BU_ "attr4" STRING;
        BA_DEF_ BU_ "attr5" ENUM "abc", "def", "ghi";
        BA_DEF_ BU_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
    )dbc";
    dbc::CDbcSource srcAttribute(ssAttribute);
    EXPECT_NO_THROW(parser.Parse(srcAttribute));

    // Attribute value
    // The use of an index instead of a value for the enum value is not part of the official standard.
    std::string ssAttrVal = R"dbc(
        BA_ "attr1" BU_ nodeTx 11;
        BA_ "attr2" BU_ nodeTx 12;
        BA_ "attr2" BU_ nodeTx 13;
        BA_ "attr3" BU_ nodeRx 3.5;
        BA_ "attr4" BU_ nodeRx "hi";
        BA_ "attr5" BU_ nodeRx "ghi";
        BA_ "attr6" BU_ nodeRx 6;
    )dbc";
    dbc::CDbcSource srcAttrVal(ssAttrVal);
    EXPECT_NO_THROW(parser.Parse(srcAttrVal));
    auto prNodeDef = parser.GetNodeDef("nodeTx");
    ASSERT_EQ(prNodeDef.first.vecAttributes.size(), 3u);
    EXPECT_EQ(prNodeDef.first.vecAttributes[0].iValue, 11);
    EXPECT_EQ(prNodeDef.first.vecAttributes[1].uiValue, 12u);
    EXPECT_EQ(prNodeDef.first.vecAttributes[2].uiValue, 13u);
    prNodeDef = parser.GetNodeDef("nodeRx");
    ASSERT_EQ(prNodeDef.first.vecAttributes.size(), 4u);
    EXPECT_EQ(prNodeDef.first.vecAttributes[0].dValue, 3.5);
    EXPECT_EQ(prNodeDef.first.vecAttributes[1].ssValue, "hi");
    EXPECT_EQ(prNodeDef.first.vecAttributes[2].ssValue, "ghi");
    EXPECT_EQ(prNodeDef.first.vecAttributes[3].ssValue, "stu");
}

TEST_F(CDbcParserTest, MessageAttributeVal)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Message attribute definition
    // The use of "n/a" and "not-used" is not part of the official standard.
    std::string ssAttribute = R"dbc(
        BA_DEF_ BO_ "attr1" INT 10 20;
        BA_DEF_ BO_ "attr2" HEX 10 20;
        BA_DEF_ BO_ "attr3" FLOAT 1.0 10.9;
        BA_DEF_ BO_ "attr4" STRING;
        BA_DEF_ BO_ "attr5" ENUM "abc", "def", "ghi";
        BA_DEF_ BO_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
    )dbc";
    dbc::CDbcSource srcAttribute(ssAttribute);
    EXPECT_NO_THROW(parser.Parse(srcAttribute));

    // Message definition
    std::string ssMsgDef = R"dbc(
        BO_ 1 msg: 8 nodeTx
            SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
        BO_ 2 msg2: 8 nodeRx
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));

    // Attribute value
    // The use of an index instead of a value for the enum value is not part of the official standard.
    std::string ssAttrVal = R"dbc(
        BA_ "attr1" BO_ 1 11;
        BA_ "attr2" BO_ 1 12;
        BA_ "attr2" BO_ 1 13;
        BA_ "attr3" BO_ 2 3.5;
        BA_ "attr4" BO_ 2 "hi";
        BA_ "attr5" BO_ 2 "ghi";
        BA_ "attr6" BO_ 2 6;
    )dbc";
    dbc::CDbcSource srcAttrVal(ssAttrVal);
    EXPECT_NO_THROW(parser.Parse(srcAttrVal));
    auto prMsgDef = parser.GetMsgDef(1);
    ASSERT_EQ(prMsgDef.first.vecAttributes.size(), 3u);
    EXPECT_EQ(prMsgDef.first.vecAttributes[0].iValue, 11);
    EXPECT_EQ(prMsgDef.first.vecAttributes[1].uiValue, 12u);
    EXPECT_EQ(prMsgDef.first.vecAttributes[2].uiValue, 13u);
    prMsgDef = parser.GetMsgDef(2);
    ASSERT_EQ(prMsgDef.first.vecAttributes.size(), 4u);
    EXPECT_EQ(prMsgDef.first.vecAttributes[0].dValue, 3.5);
    EXPECT_EQ(prMsgDef.first.vecAttributes[1].ssValue, "hi");
    EXPECT_EQ(prMsgDef.first.vecAttributes[2].ssValue, "ghi");
    EXPECT_EQ(prMsgDef.first.vecAttributes[3].ssValue, "stu");
}

TEST_F(CDbcParserTest, SignalAttributeVal)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Signal attribute definition
    // The use of "n/a" and "not-used" is not part of the official standard.
    std::string ssAttribute = R"dbc(
        BA_DEF_ SG_ "attr1" INT 10 20;
        BA_DEF_ SG_ "attr2" HEX 10 20;
        BA_DEF_ SG_ "attr3" FLOAT 1.0 10.9;
        BA_DEF_ SG_ "attr4" STRING;
        BA_DEF_ SG_ "attr5" ENUM "abc", "def", "ghi";
        BA_DEF_ SG_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
    )dbc";
    dbc::CDbcSource srcAttribute(ssAttribute);
    EXPECT_NO_THROW(parser.Parse(srcAttribute));

    // Message definition
    std::string ssMsgDef = R"dbc(
        BO_ 1 msg: 8 nodeTx
            SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
            SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
        BO_ 2 msg2: 8 nodeRx
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));

    // Attribute value
    // The use of an index instead of a value for the enum value is not part of the official standard.
    std::string ssAttrVal = R"dbc(
        BA_ "attr1" SG_ 1 sig1 11;
        BA_ "attr2" SG_ 1 sig1 12;
        BA_ "attr2" SG_ 1 sig2 13;
        BA_ "attr3" SG_ 1 sig2 3.5;
        BA_ "attr4" SG_ 1 sig3 "hi";
        BA_ "attr5" SG_ 1 sig3 "ghi";
        BA_ "attr6" SG_ 1 sig3 6;
    )dbc";
    dbc::CDbcSource srcAttrVal(ssAttrVal);
    EXPECT_NO_THROW(parser.Parse(srcAttrVal));
    auto prSigDef = parser.GetSignalDef(1, "sig1");
    ASSERT_EQ(prSigDef.first.vecAttributes.size(), 2u);
    EXPECT_EQ(prSigDef.first.vecAttributes[0].iValue, 11);
    EXPECT_EQ(prSigDef.first.vecAttributes[1].uiValue, 12u);
    prSigDef = parser.GetSignalDef(1, "sig2");
    ASSERT_EQ(prSigDef.first.vecAttributes.size(), 2u);
    EXPECT_EQ(prSigDef.first.vecAttributes[0].uiValue, 13u);
    EXPECT_EQ(prSigDef.first.vecAttributes[1].dValue, 3.5);
    prSigDef = parser.GetSignalDef(1, "sig3");
    ASSERT_EQ(prSigDef.first.vecAttributes.size(), 3u);
    EXPECT_EQ(prSigDef.first.vecAttributes[0].ssValue, "hi");
    EXPECT_EQ(prSigDef.first.vecAttributes[1].ssValue, "ghi");
    EXPECT_EQ(prSigDef.first.vecAttributes[2].ssValue, "stu");
}

TEST_F(CDbcParserTest, EnvVarAttributeVal)
{
    dbc::CDbcParser parser;

    // Node definition
    std::string ssValidNodeDef = "BU_: nodeTx nodeRx";
    dbc::CDbcSource srcValidNodeDef(ssValidNodeDef);
    EXPECT_NO_THROW(parser.Parse(srcValidNodeDef));
    EXPECT_TRUE(parser.HasNodeDef("nodeTx"));
    EXPECT_TRUE(parser.HasNodeDef("nodeRx"));

    // Environment variable attribute definition
    // The use of "n/a" and "not-used" is not part of the official standard.
    std::string ssAttribute = R"dbc(
        BA_DEF_ EV_ "attr1" INT 10 20;
        BA_DEF_ EV_ "attr2" HEX 10 20;
        BA_DEF_ EV_ "attr3" FLOAT 1.0 10.9;
        BA_DEF_ EV_ "attr4" STRING;
        BA_DEF_ EV_ "attr5" ENUM "abc", "def", "ghi";
        BA_DEF_ EV_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
    )dbc";
    dbc::CDbcSource srcAttribute(ssAttribute);
    EXPECT_NO_THROW(parser.Parse(srcAttribute));

    // Environment variable definition
    std::string ssEnvVarDef = R"dbc(
    EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
    EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
    EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)dbc";
    dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
    EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));

    // Attribute value
    // The use of an index instead of a value for the enum value is not part of the official standard.
    std::string ssAttrVal = R"dbc(
        BA_ "attr1" EV_ var1 11;
        BA_ "attr2" EV_ var1 12;
        BA_ "attr2" EV_ var2 13;
        BA_ "attr3" EV_ var2 3.5;
        BA_ "attr4" EV_ var3 "hi";
        BA_ "attr5" EV_ var3 "ghi";
        BA_ "attr6" EV_ var3 6;
    )dbc";
    dbc::CDbcSource srcAttrVal(ssAttrVal);
    EXPECT_NO_THROW(parser.Parse(srcAttrVal));
    auto prEnvVarDef = parser.GetEnvVarDef("var1");
    ASSERT_EQ(prEnvVarDef.first.vecAttributes.size(), 2u);
    EXPECT_EQ(prEnvVarDef.first.vecAttributes[0].iValue, 11);
    EXPECT_EQ(prEnvVarDef.first.vecAttributes[1].uiValue, 12u);
    prEnvVarDef = parser.GetEnvVarDef("var2");
    ASSERT_EQ(prEnvVarDef.first.vecAttributes.size(), 2u);
    EXPECT_EQ(prEnvVarDef.first.vecAttributes[0].uiValue, 13u);
    EXPECT_EQ(prEnvVarDef.first.vecAttributes[1].dValue, 3.5);
    prEnvVarDef = parser.GetEnvVarDef("var3");
    ASSERT_EQ(prEnvVarDef.first.vecAttributes.size(), 3u);
    EXPECT_EQ(prEnvVarDef.first.vecAttributes[0].ssValue, "hi");
    EXPECT_EQ(prEnvVarDef.first.vecAttributes[1].ssValue, "ghi");
    EXPECT_EQ(prEnvVarDef.first.vecAttributes[2].ssValue, "stu");
}

TEST_F(CDbcParserTest, SignalExtendedMultiplexing)
{
    dbc::CDbcParser parser;

    // Message definition
    std::string ssMsgDef = R"dbc(
        BO_ 100 MuxMsg: 1 Vector__XXX
            SG_ Mux_4 m2 : 6|2@1+ (1,0) [0|0] "" Vector__XXX
            SG_ Mux_3 m3M : 4|2@1+ (1,0) [0|0] "" Vector__XXX
            SG_ Mux_2 m3M : 2|2@1+ (1,0) [0|0] "" Vector__XXX
            SG_ Mux_1 M : 0|2@1+ (1,0) [0|0] "" Vector__XXX

        SG_MUL_VAL_ 100 Mux_2 Mux_1 3-3, 5-10;
        SG_MUL_VAL_ 100 Mux_3 Mux_2 3-3;
        SG_MUL_VAL_ 100 Mux_4 Mux_3 2-2;
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));

    auto prSigDef = parser.GetSignalDef(100, "Mux_4");
    EXPECT_TRUE(prSigDef.second);
    EXPECT_EQ(prSigDef.first.uiMultiplexBitmask, static_cast<uint32_t>(dbc::SSignalDef::EMultiplexBitmask::mltplx_val));
    ASSERT_EQ(prSigDef.first.vecExtMultiplex.size(), 1u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].rsMultiplexor.ssName, "Mux_3");
    ASSERT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges.size(), 1u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges[0].first, 2u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges[0].second, 2u);
    prSigDef = parser.GetSignalDef(100, "Mux_3");
    EXPECT_TRUE(prSigDef.second);
    EXPECT_EQ(prSigDef.first.uiMultiplexBitmask, static_cast<uint32_t>(dbc::SSignalDef::EMultiplexBitmask::mltplx_val) |
        static_cast<uint32_t>(dbc::SSignalDef::EMultiplexBitmask::mltplx_switch));
    ASSERT_EQ(prSigDef.first.vecExtMultiplex.size(), 1u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].rsMultiplexor.ssName, "Mux_2");
    ASSERT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges.size(), 1u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges[0].first, 3u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges[0].second, 3u);
    prSigDef = parser.GetSignalDef(100, "Mux_2");
    EXPECT_TRUE(prSigDef.second);
    EXPECT_EQ(prSigDef.first.uiMultiplexBitmask, static_cast<uint32_t>(dbc::SSignalDef::EMultiplexBitmask::mltplx_val) |
        static_cast<uint32_t>(dbc::SSignalDef::EMultiplexBitmask::mltplx_switch));
    ASSERT_EQ(prSigDef.first.vecExtMultiplex.size(), 1u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].rsMultiplexor.ssName, "Mux_1");
    ASSERT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges.size(), 2u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges[0].first, 3u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges[0].second, 3u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges[1].first, 5u);
    EXPECT_EQ(prSigDef.first.vecExtMultiplex[0].vecRanges[1].second, 10u);
    prSigDef = parser.GetSignalDef(100, "Mux_1");
    EXPECT_TRUE(prSigDef.second);
    EXPECT_EQ(prSigDef.first.uiMultiplexBitmask, static_cast<uint32_t>(dbc::SSignalDef::EMultiplexBitmask::mltplx_switch));
    ASSERT_EQ(prSigDef.first.vecExtMultiplex.size(), 0u);
}

TEST_F(CDbcParserTest, ExampleDBC1)
{
    dbc::CDbcParser parser;

    // Message definition
    std::string ssMsgDef = R"dbc(
VERSION ""

NS_ :
    NS_DESC_
    CM_
    BA_DEF_
    BA_
    VAL_
    CAT_DEF_
    CAT_
    FILTER
    BA_DEF_DEF_
    EV_DATA_
    ENVVAR_DATA_
    SGTYPE_
    SGTYPE_VAL_
    BA_DEF_SGTYPE_
    BA_SGTYPE_
    SIG_TYPE_REF_
    VAL_TABLE_
    SIG_GROUP_
    SIG_VALTYPE_
    SIGTYPE_VALTYPE_
    BO_TX_BU_
    BA_DEF_REL_
    BA_REL_
    BA_DEF_DEF_REL_
    BU_SG_REL_
    BU_EV_REL_
    BU_BO_REL_

BS_:

BU_: Engine Gateway

BO_ 100 EngineData: 8 Engine
    SG_ PetrolLevel : 24|8@1+ (1,0) [0|255] "l" Gateway
    SG_ EngPower : 48|16@1+ (0.01,0) [0|150] "kW" Gateway
    SG_ EngForce : 32|16@1+ (1,0) [0|0] "N" Gateway
    SG_ IdleRunning : 23|1@1+ (1,0) [0|0] "" Gateway
    SG_ EngTemp : 16|7@1+ (2,-50) [-50|150] "degC" Gateway
    SG_ EngSpeed : 0|16@1+ (1,0) [0|8000] "rpm" Gateway

CM_ "CAN communication matrix for power train electronics
*******************************************************
implemented: turn lights, warning lights, windows";

VAL_ 100 IdleRunning 0 "Running" 1 "Idle" ;
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));
}
TEST_F(CDbcParserTest, ExampleDBC2)
{
    dbc::CDbcParser parser;

    // Message definition
    std::string ssMsgDef = R"dbc(
VERSION ""


NS_ :
	NS_DESC_
	CM_
	BA_DEF_
	BA_
	VAL_
	CAT_DEF_
	CAT_
	FILTER
	BA_DEF_DEF_
	EV_DATA_
	ENVVAR_DATA_
	SGTYPE_
	SGTYPE_VAL_
	BA_DEF_SGTYPE_
	BA_SGTYPE_
	SIG_TYPE_REF_
	VAL_TABLE_
	SIG_GROUP_
	SIG_VALTYPE_
	SIGTYPE_VALTYPE_
	BO_TX_BU_
	BA_DEF_REL_
	BA_REL_
	BA_DEF_DEF_REL_
	BU_SG_REL_
	BU_EV_REL_
	BU_BO_REL_
	SG_MUL_VAL_

BS_:

BU_: ProConnect Goldbox DataLynx HMI MAB
VAL_TABLE_ HMI_Fct_Req 8 "FCT_DEACTVN_REQ" 7 "FCT_ACTVN_OTA_REQ" 6 "FCT_ACTVN_SAVETHESPOILER_CFMD" 5 "FCT_ACTVN_SAVETHESPOILER_REQ" 4 "FCT_ACTVN_CRABWALK_CFMD" 3 "FCT_ACTVN_CRABWALK_REQ" 2 "FCT_ACTVN_AI4MTN_CFMD" 1 "FCT_ACTVN_AI4MTN_REQ" 0 "FCT_ACTVN_NONE" ;
VAL_TABLE_ Lateral_Longitudinal_AI4Motion 3 "LONGITUDINAL_CTRL_REQ" 2 "LONGITUDINAL_AND_LATERAL" 1 "LATERAL_CTRL_REQ" 0 "NONE" ;
VAL_TABLE_ OpenLoop_ClosedLoop_AI4Motion 2 "OPEN_LOOP_REQ" 1 "CLOSED_LOOP_REQ" 0 "NONE" ;
VAL_TABLE_ SOVD_states 2 "SOVD_SHOWCASE_ACTIVE" 1 "SOVD_SHOWCASE_DEACTIVE" 0 "SOVD_NONE" ;
VAL_TABLE_ OTA_states 7 "OTA_DOWNLOAD_FAILED" 6 "OTA_INSTALL_FAILED" 5 "OTA_INSTALL_FINISHED" 4 "OTA_INSTALL_START" 3 "OTA_DOWNLOAD_FINISHED" 2 "OTA_DOWNLOAD_START" 1 "OTA_AVAILABLE" 0 "OTA_NONE" ;
VAL_TABLE_ AI4Motion_Variant 4 "NONE" 3 "VARIANT_4" 2 "VARIANT_3" 1 "VARIANT_2" 0 "VARIANT_1" ;


BO_ 3221225472 VECTOR__INDEPENDENT_SIG_MSG: 0 Vector__XXX
 SG_ New_Signal_25 : 0|64@1- (1,0) [0|0] "" Vector__XXX

BO_ 6 Test: 8 Vector__XXX
 SG_ Signal_1 : 7|4@0+ (1,0) [0|0] "" Vector__XXX
 SG_ Signal_2 : 3|8@0+ (1,0) [0|0] "" Vector__XXX
 SG_ Signal_3 : 11|6@0+ (1,0) [0|0] "" Vector__XXX
 SG_ Signal_4 : 21|6@0+ (1,0) [0|0] "" Vector__XXX
 SG_ Signal_5 : 31|8@0+ (1,0) [0|0] "" Vector__XXX
 SG_ Signal_6 : 39|32@0+ (1,0) [0|0] "" Vector__XXX

BO_ 5 ProConnect_OTA_Status: 8 ProConnect
 SG_ ProConnect_OTA_Sts : 7|8@0+ (1,0) [0|0] "enum"  HMI,MAB

BO_ 4 MAB_HMI_Feedback: 6 MAB
 SG_ MAB_Fault_codes : 23|32@0+ (1,0) [0|0] "bit coded"  HMI
 SG_ MAB_Global_activation_status : 7|16@0+ (1,0) [0|0] "bit coded"  HMI

BO_ 3 HMI_OTA_SOVD: 2 HMI

BO_ 2 DataLynx_AI4Motion: 7 DataLynx
 SG_ DataLynx_Brake_Deceleration_Req : 55|8@0+ (1,0) [0|0] "m/s^2"  MAB
 SG_ DataLynx_Brake_Torque_Req : 47|8@0+ (1,0) [0|0] "Nm"  MAB
 SG_ DataLynx_Camera_Rolling_Counter : 39|8@0+ (1,0) [0|14] "unitless integer"  MAB
 SG_ DataLynx_Rolling_Counter : 31|8@0+ (1,0) [0|14] "unitless integer"  MAB
 SG_ DataLynx_Steering_Angle_Request : 23|8@0- (1,0) [0|0] "radians"  MAB
 SG_ DataLynx_Brake_Perc_Request : 15|8@0+ (1,0) [0|100] "percent"  MAB
 SG_ DataLynx_Acceleration_Request : 7|8@0+ (1,0) [0|100] "percent"  MAB

BO_ 1 HMI_Requests: 4 HMI
 SG_ HMI_Drvr_Req : 31|8@0+ (1,0) [0|0] "enum"  ProConnect,MAB
 SG_ HMI_open_closed_loop_Req : 23|8@0+ (1,0) [0|0] ""  MAB
 SG_ HMI_Lateral_Long_Ctrl_Req : 15|8@0+ (1,0) [0|0] ""  MAB
 SG_ HMI_Algo_Variant_Request : 7|8@0- (1,0) [0|0] "enum"  MAB

BO_ 0 MAB_AI4Motion_Actvn: 4 MAB
 SG_ MAB_AI4Motion_Algo_Var_Selected : 31|8@0+ (1,0) [0|0] "enum"  DataLynx
 SG_ MAB_Actual_Steering_angle : 23|8@0- (1,0) [0|0] "radian"  DataLynx
 SG_ MAB_Actual_vehicle_speed : 15|8@0+ (1,0) [0|0] "m/sec"  DataLynx
 SG_ MAB_Activation_AI4Motion : 7|8@0+ (1,0) [0|0] "enum"  DataLynx



CM_ BO_ 3221225472 "This is a message for not used signals, created by Vector CANdb++ DBC OLE DB Provider.";
CM_ SG_ 4 MAB_Fault_codes "Bit coded signal

";
CM_ SG_ 4 MAB_Global_activation_status "Bit coded signal";
CM_ SG_ 2 DataLynx_Camera_Rolling_Counter "Replace this signal with an error signal (flag) which is detected by VAPI if camera image is frozen";
CM_ SG_ 2 DataLynx_Steering_Angle_Request "Clarify with Daniel if Radlenkwinkel oder Lenkradwinkel";
BA_DEF_ BO_  "GenMsgStartDelayTime" INT 0 0;
BA_DEF_ BO_  "GenMsgSendType" INT 0 0;
BA_DEF_ BO_  "GenMsgRequestable" INT 0 0;
BA_DEF_ BO_  "GenMsgNrOfRepetition" INT 0 0;
BA_DEF_ BO_  "GenMsgLSupport" INT 0 0;
BA_DEF_ BO_  "GenMsgFastOnStart" INT 0 0;
BA_DEF_ BO_  "GenMsgDelayTime" INT 0 0;
BA_DEF_ BO_  "GenMsgCycleTimeFast" INT 0 1000;
BA_DEF_ BO_  "GenMsgCycleTime" INT 0 1000;
BA_DEF_  "BusType" STRING ;
BA_DEF_DEF_  "GenMsgStartDelayTime" 0;
BA_DEF_DEF_  "GenMsgSendType" 0;
BA_DEF_DEF_  "GenMsgRequestable" 0;
BA_DEF_DEF_  "GenMsgNrOfRepetition" 0;
BA_DEF_DEF_  "GenMsgLSupport" 0;
BA_DEF_DEF_  "GenMsgFastOnStart" 0;
BA_DEF_DEF_  "GenMsgDelayTime" 0;
BA_DEF_DEF_  "GenMsgCycleTimeFast" 100;
BA_DEF_DEF_  "GenMsgCycleTime" 100;
BA_DEF_DEF_  "BusType" "";
BA_ "BusType" "CAN";
VAL_ 5 ProConnect_OTA_Sts 7 "OTA_DOWNLOAD_FAILED" 6 "OTA_INSTALL_FAILED" 5 "OTA_INSTALL_FINISHED" 4 "OTA_INSTALL_START" 3 "OTA_DOWNLOAD_FINISHED" 2 "OTA_DOWNLOAD_START" 1 "OTA_AVAILABLE" 0 "OTA_NONE" ;
VAL_ 1 HMI_Drvr_Req 8 "FCT_DEACTVN_REQ" 7 "FCT_ACTVN_OTA_REQ" 6 "FCT_ACTVN_SAVETHESPOILER_CFMD" 5 "FCT_ACTVN_SAVETHESPOILER_REQ" 4 "FCT_ACTVN_CRABWALK_CFMD" 3 "FCT_ACTVN_CRABWALK_REQ" 2 "FCT_ACTVN_AI4MTN_CFMD" 1 "FCT_ACTVN_AI4MTN_REQ" 0 "FCT_ACTVN_NONE" ;
VAL_ 1 HMI_open_closed_loop_Req 2 "OPEN_LOOP_REQ" 1 "CLOSED_LOOP_REQ" 0 "NONE" ;
VAL_ 1 HMI_Lateral_Long_Ctrl_Req 3 "LONGITUDINAL_CTRL_REQ" 2 "LONGITUDINAL_AND_LATERAL" 1 "LATERAL_CTRL_REQ" 0 "NONE" ;
VAL_ 1 HMI_Algo_Variant_Request 4 "NONE" 3 "VARIANT_4" 2 "VARIANT_3" 1 "VARIANT_2" 0 "VARIANT_1" ;
VAL_ 0 MAB_AI4Motion_Algo_Var_Selected 4 "NONE" 3 "VARIANT_4" 2 "VARIANT_3" 1 "VARIANT_2" 0 "VARIANT_1" ;
VAL_ 0 MAB_Activation_AI4Motion 3 "LONGITUDINAL_CTRL_REQ" 2 "LONGITUDINAL_AND_LATERAL" 1 "LATERAL_CTRL_REQ" 0 "NONE" ;
SIG_VALTYPE_ 3221225472 New_Signal_25 : 2;    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));
}
TEST_F(CDbcParserTest, ExampleDBC3)
{
    dbc::CDbcParser parser;

    // Message definition
    std::string ssMsgDef = R"dbc(
VERSION ""


                        NS_ :
                        BA_
                        BA_DEF_
                        BA_DEF_DEF_
                        BA_DEF_DEF_REL_
                        BA_DEF_REL_
                        BA_DEF_SGTYPE_
                        BA_REL_
                        BA_SGTYPE_
                        BO_TX_BU_
                        BU_BO_REL_
                        BU_EV_REL_
                        BU_SG_REL_
                        CAT_
                        CAT_DEF_
                        CM_
                        ENVVAR_DATA_
                        EV_DATA_
                        FILTER
                        NS_DESC_
                        SGTYPE_
                        SGTYPE_VAL_
                        SG_MUL_VAL_
                        SIGTYPE_VALTYPE_
                        SIG_GROUP_
                        SIG_TYPE_REF_
                        SIG_VALTYPE_
                        VAL_
                        VAL_TABLE_


                        BS_:


                        BU_: DBG DRIVER IO MOTOR SENSOR


                        BO_ 100 DRIVER_HEARTBEAT: 1 DRIVER
                        SG_ DRIVER_HEARTBEAT_cmd : 0|8@1+ (1,0) [0|0] "" SENSOR,MOTOR


                        BO_ 500 IO_DEBUG: 4 IO
                        SG_ IO_DEBUG_test_unsigned : 0|8@1+ (1,0) [0|0] "" DBG
                        SG_ IO_DEBUG_test_enum : 8|8@1+ (1,0) [0|0] "" DBG
                        SG_ IO_DEBUG_test_signed : 16|8@1- (1,0) [0|0] "" DBG
                        SG_ IO_DEBUG_test_float : 24|8@1+ (0.5,0) [0|0] "" DBG


                        BO_ 101 MOTOR_CMD: 1 DRIVER
                        SG_ MOTOR_CMD_steer : 0|4@1- (1,-5) [-5|5] "" MOTOR
                        SG_ MOTOR_CMD_drive : 4|4@1+ (1,0) [0|9] "" MOTOR


                        BO_ 400 MOTOR_STATUS: 3 MOTOR
                        SG_ MOTOR_STATUS_wheel_error : 0|1@1+ (1,0) [0|0] "" DRIVER,IO
                        SG_ MOTOR_STATUS_speed_kph : 8|16@1+ (0.001,0) [0|0] "kph" DRIVER,IO


                        BO_ 200 SENSOR_SONARS: 8 SENSOR
                        SG_ SENSOR_SONARS_mux M : 0|4@1+ (1,0) [0|0] "" DRIVER,IO
                        SG_ SENSOR_SONARS_err_count : 4|12@1+ (1,0) [0|0] "" DRIVER,IO
                        SG_ SENSOR_SONARS_left m0 : 16|12@1+ (0.1,0) [0|0] "" DRIVER,IO
                        SG_ SENSOR_SONARS_middle m0 : 28|12@1+ (0.1,0) [0|0] "" DRIVER,IO
                        SG_ SENSOR_SONARS_right m0 : 40|12@1+ (0.1,0) [0|0] "" DRIVER,IO
                        SG_ SENSOR_SONARS_rear m0 : 52|12@1+ (0.1,0) [0|0] "" DRIVER,IO
                        SG_ SENSOR_SONARS_no_filt_left m1 : 16|12@1+ (0.1,0) [0|0] "" DBG
                        SG_ SENSOR_SONARS_no_filt_middle m1 : 28|12@1+ (0.1,0) [0|0] "" DBG
                        SG_ SENSOR_SONARS_no_filt_right m1 : 40|12@1+ (0.1,0) [0|0] "" DBG
                        SG_ SENSOR_SONARS_no_filt_rear m1 : 52|12@1+ (0.1,0) [0|0] "" DBG


                        CM_ BU_ DRIVER "The driver controller driving the car";
                        CM_ BU_ MOTOR "The motor controller of the car";
                        CM_ BU_ SENSOR "The sensor controller of the car";
                        CM_ BO_ 100 "Sync message used to synchronize the controllers";


                        BA_DEF_ "BusType" STRING ;
                        BA_DEF_ BO_ "GenMsgCycleTime" INT 0 0;
                        BA_DEF_ SG_ "FieldType" STRING ;


                        BA_DEF_DEF_ "BusType" "CAN";
                        BA_DEF_DEF_ "FieldType" "";
                        BA_DEF_DEF_ "GenMsgCycleTime" 0;


                        BA_ "GenMsgCycleTime" BO_ 100 1000;
                        BA_ "GenMsgCycleTime" BO_ 500 100;
                        BA_ "GenMsgCycleTime" BO_ 101 100;
                        BA_ "GenMsgCycleTime" BO_ 400 100;
                        BA_ "GenMsgCycleTime" BO_ 200 100;
                        BA_ "FieldType" SG_ 100 DRIVER_HEARTBEAT_cmd "DRIVER_HEARTBEAT_cmd";
                        BA_ "FieldType" SG_ 500 IO_DEBUG_test_enum "IO_DEBUG_test_enum";


                        VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0
                        "DRIVER_HEARTBEAT_cmd_NOOP" ;
                        VAL_ 500 IO_DEBUG_test_enum 2 "IO_DEBUG_test2_enum_two" 1 "IO_DEBUG_test2_enum_one" ;
    )dbc";
    dbc::CDbcSource srcMsgDef(ssMsgDef);
    EXPECT_NO_THROW(parser.Parse(srcMsgDef));
}
