diff --git a/DbcParserLib.Tests/ExtraMessageTransmitterLineParserTests.cs b/DbcParserLib.Tests/ExtraMessageTransmitterLineParserTests.cs new file mode 100644 index 0000000..bd7112c --- /dev/null +++ b/DbcParserLib.Tests/ExtraMessageTransmitterLineParserTests.cs @@ -0,0 +1,231 @@ +using DbcParserLib.Observers; +using NUnit.Framework; +using System.Linq; + +namespace DbcParserLib.Tests +{ + [TestFixture] + public class ExtraMessageTransmitterLineParserTests + { + [Test] + public void ParseOneExtraTransmitters() + { + var dbcString = @" +BO_ 200 TestMessage: 1 TestTransmitter + SG_ Test : 0|8@1+ (0.1,0) [0|0] """" DBG + +BO_TX_BU_ 200 : Transmitter2;"; + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.Multiple(() => + { + Assert.That(errorList, Has.Count.EqualTo(0)); + Assert.That(dbc.Messages.Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.SelectMany(m => m.Signals).Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Count, Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.First(), Is.EqualTo("Transmitter2")); + }); + } + + [Test] + public void ParseTwoExtraTransmitters() + { + var dbcString = @" +BO_ 200 TestMessage: 1 TestTransmitter + SG_ Test : 0|8@1+ (0.1,0) [0|0] """" DBG + +BO_TX_BU_ 200 : Transmitter2,Transmitter3;"; + + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.Multiple(() => + { + Assert.That(errorList, Has.Count.EqualTo(0)); + Assert.That(dbc.Messages.Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.SelectMany(m => m.Signals).Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Count, Is.EqualTo(2)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.First(), Is.EqualTo("Transmitter2")); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Last(), Is.EqualTo("Transmitter3")); + }); + } + + [Test] + public void MissingLineTerminationParsingErrorIsObserved() + { + var dbcString = @"BO_TX_BU_ 200 : Transmitter2"; + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.That(errorList, Has.Count.EqualTo(1)); + } + + [Test] + public void LineTerminationWithLeadingSpace() + { + var dbcString = @" +BO_ 200 TestMessage: 1 TestTransmitter + SG_ Test : 0|8@1+ (0.1,0) [0|0] """" DBG + +BO_TX_BU_ 200 : Transmitter2 ;"; + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.Multiple(() => + { + Assert.That(errorList, Has.Count.EqualTo(0)); + Assert.That(dbc.Messages.Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.SelectMany(m => m.Signals).Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Count, Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.First(), Is.EqualTo("Transmitter2")); + }); + } + + [Test] + public void LineTerminationWithLeadingSpaceMultiDefinition() + { + var dbcString = @" +BO_ 200 TestMessage: 1 TestTransmitter + SG_ Test : 0|8@1+ (0.1,0) [0|0] """" DBG + +BO_TX_BU_ 200 : Transmitter2, Transmitter3 ;"; + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.Multiple(() => + { + Assert.That(errorList, Has.Count.EqualTo(0)); + Assert.That(dbc.Messages.Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.SelectMany(m => m.Signals).Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Count, Is.EqualTo(2)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.First(), Is.EqualTo("Transmitter2")); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Last(), Is.EqualTo("Transmitter3")); + }); + } + + [Test] + public void ParseTwoExtraTransmittersLessSpaces() + { + var dbcString = @" +BO_ 200 TestMessage: 1 TestTransmitter + SG_ Test : 0|8@1+ (0.1,0) [0|0] """" DBG + +BO_TX_BU_ 200:Transmitter2,Transmitter3;"; + + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.Multiple(() => + { + Assert.That(errorList, Has.Count.EqualTo(0)); + Assert.That(dbc.Messages.Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.SelectMany(m => m.Signals).Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Count, Is.EqualTo(2)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.First(), Is.EqualTo("Transmitter2")); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Last(), Is.EqualTo("Transmitter3")); + }); + } + + [Test] + public void ParseTwoExtraTransmittersMoreSpaces() + { + var dbcString = @" +BO_ 200 TestMessage: 1 TestTransmitter + SG_ Test : 0|8@1+ (0.1,0) [0|0] """" DBG + +BO_TX_BU_ 200 : Transmitter2 , Transmitter3 ;"; + + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.Multiple(() => + { + Assert.That(errorList, Has.Count.EqualTo(0)); + Assert.That(dbc.Messages.Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.SelectMany(m => m.Signals).Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Count, Is.EqualTo(2)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.First(), Is.EqualTo("Transmitter2")); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Last(), Is.EqualTo("Transmitter3")); + }); + } + + [Test] + public void ParsingErrorIsObserved() + { + var dbcString = @"BO_TX_BU_ 200 ; Transmitter2, Transmitter3;"; + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.That(errorList, Has.Count.EqualTo(1)); + } + + [Test] + public void ParseExtraTransmittersDuplicateErrorIsObserved() + { + var dbcString = @" +BO_ 200 TestMessage: 1 TestTransmitter + SG_ Test : 0|8@1+ (0.1,0) [0|0] """" DBG + +BO_TX_BU_ 200 : Transmitter2 , Transmitter2 ;"; + + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.Multiple(() => + { + Assert.That(errorList, Has.Count.EqualTo(1)); + Assert.That(dbc.Messages.Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.SelectMany(m => m.Signals).Count(), Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.Count, Is.EqualTo(1)); + Assert.That(dbc.Messages.First().AdditionalTransmitters.First(), Is.EqualTo("Transmitter2")); + }); + } + + public void ParseExtraTransmittersMessageNotFoundErrorIsObserved() + { + var dbcString = @" +BO_ 200 TestMessage: 1 TestTransmitter + SG_ Test : 0|8@1+ (0.1,0) [0|0] """" DBG + +BO_TX_BU_ 201 : Transmitter2, Transmitter3 ;"; + + var failureObserver = new SimpleFailureObserver(); + Parser.SetParsingFailuresObserver(failureObserver); + var dbc = Parser.Parse(dbcString); + var errorList = failureObserver.GetErrorList(); + + Assert.Multiple(() => + { + Assert.That(errorList, Has.Count.EqualTo(1)); + }); + } + } +} diff --git a/DbcParserLib/DbcBuilder.cs b/DbcParserLib/DbcBuilder.cs index ecd2f63..67d5cb8 100644 --- a/DbcParserLib/DbcBuilder.cs +++ b/DbcParserLib/DbcBuilder.cs @@ -180,6 +180,18 @@ public void AddMessageCustomProperty(string propertyName, uint messageId, string m_observer.PropertyNameNotFound(propertyName); } + public void AddMessageAdditionalTransmitters(uint messageId, string[] additonalTransmitters) + { + if (m_messages.TryGetValue(messageId, out var message)) + { + message.AdditionalTransmitters = additonalTransmitters; + } + else + { + m_observer.MessageIdNotFound(messageId); + } + } + public void AddSignalCustomProperty(string propertyName, uint messageId, string signalName, string value, bool isNumeric) { if (m_customProperties[CustomPropertyObjectType.Signal].TryGetValue(propertyName, out var customProperty)) diff --git a/DbcParserLib/IDbcBuilder.cs b/DbcParserLib/IDbcBuilder.cs index 17c0046..47b4d7a 100644 --- a/DbcParserLib/IDbcBuilder.cs +++ b/DbcParserLib/IDbcBuilder.cs @@ -22,6 +22,7 @@ internal interface IDbcBuilder void AddGlobalCustomProperty(string propertyName, string value, bool isNumeric); void AddEnvironmentVariableCustomProperty(string propertyName, string variableName, string value, bool isNumeric); void AddMessageCustomProperty(string propertyName, uint messageId, string value, bool isNumeric); + void AddMessageAdditionalTransmitters(uint messageId, string[] additonalTransmitters); void AddSignalCustomProperty(string propertyName, uint messageId, string signalName, string value, bool isNumeric); void AddEnvironmentVariable(string variableName, EnvironmentVariable environmentVariable); void AddEnvironmentVariableComment(string variableName, string comment); diff --git a/DbcParserLib/Model/Message.cs b/DbcParserLib/Model/Message.cs index 018806f..4af130c 100644 --- a/DbcParserLib/Model/Message.cs +++ b/DbcParserLib/Model/Message.cs @@ -9,6 +9,7 @@ internal class ImmutableMessage public string Name { get; } public ushort DLC { get; } public string Transmitter { get; } + public IReadOnlyCollection AdditionalTransmitters { get; } public string Comment { get; } public int CycleTime { get; } public IReadOnlyList Signals { get; } @@ -23,6 +24,7 @@ internal ImmutableMessage(Message message, IReadOnlyList signal Name = message.Name; DLC = message.DLC; Transmitter = message.Transmitter; + AdditionalTransmitters = message.AdditionalTransmitters; Comment = message.Comment; CycleTime = cycleTime; Signals = signals; @@ -39,6 +41,7 @@ public class Message public string Name; public ushort DLC; public string Transmitter; + public string[] AdditionalTransmitters; public string Comment; public List Signals = new List(); diff --git a/DbcParserLib/Observers/IParseFailureObserver.cs b/DbcParserLib/Observers/IParseFailureObserver.cs index 003752d..875be68 100644 --- a/DbcParserLib/Observers/IParseFailureObserver.cs +++ b/DbcParserLib/Observers/IParseFailureObserver.cs @@ -36,6 +36,8 @@ public interface IParseFailureObserver void TableMapNameNotFound(string tableName); void PropertyValueOutOfBound(string propertyName, string value); void PropertyValueOutOfIndex(string propertyName, string index); + void ExtraMessageTransmittersSyntaxError(); + void ExtraMessageTransmittersDuplicate(uint messageId, string duplicateTransmitter); void UnknownLine(); void NoMessageFound(); void Clear(); diff --git a/DbcParserLib/Observers/SilentFailureObserver.cs b/DbcParserLib/Observers/SilentFailureObserver.cs index c50f4ec..eb96a9c 100644 --- a/DbcParserLib/Observers/SilentFailureObserver.cs +++ b/DbcParserLib/Observers/SilentFailureObserver.cs @@ -132,6 +132,14 @@ public void PropertyValueOutOfIndex(string propertyName, string index) { } + public void ExtraMessageTransmittersSyntaxError() + { + } + + public void ExtraMessageTransmittersDuplicate(uint messageId, string duplicateTransmitter) + { + } + public void UnknownLine() { } diff --git a/DbcParserLib/Observers/SimpleFailureObserver.cs b/DbcParserLib/Observers/SimpleFailureObserver.cs index abe7db0..45e0a12 100644 --- a/DbcParserLib/Observers/SimpleFailureObserver.cs +++ b/DbcParserLib/Observers/SimpleFailureObserver.cs @@ -174,6 +174,16 @@ public void PropertyValueOutOfIndex(string propertyName, string index) AddError($"Out of index value [{index}] for '{propertyName}' property"); } + public void ExtraMessageTransmittersSyntaxError() + { + AddError("[BO_TX_BU_] Extra message transmitters syntax error"); + } + + public void ExtraMessageTransmittersDuplicate(uint messageId, string duplicateTransmitter) + { + AddError($"Duplicate additional transmitter '{duplicateTransmitter}' in message '{messageId}'"); + } + public void UnknownLine() { AddError("Unknown syntax"); diff --git a/DbcParserLib/Parser.cs b/DbcParserLib/Parser.cs index f4ec32b..3b4b18a 100644 --- a/DbcParserLib/Parser.cs +++ b/DbcParserLib/Parser.cs @@ -26,6 +26,7 @@ private static void CreateLineParsers() new PropertiesLineParser(m_parseObserver), new EnvironmentVariableLineParser(m_parseObserver), new EnvironmentDataVariableLineParser(m_parseObserver), + new ExtraMessageTransmitterLineParser(m_parseObserver), new UnknownLineParser(m_parseObserver) // Used as a catch all }; } diff --git a/DbcParserLib/Parsers/ExtraMessageTransmitterLineParser.cs b/DbcParserLib/Parsers/ExtraMessageTransmitterLineParser.cs new file mode 100644 index 0000000..9f52d32 --- /dev/null +++ b/DbcParserLib/Parsers/ExtraMessageTransmitterLineParser.cs @@ -0,0 +1,57 @@ +using DbcParserLib.Observers; +using System.Collections.Generic; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace DbcParserLib.Parsers +{ + internal class ExtraMessageTransmitterLineParser : ILineParser + { + private const string MessageId = "Id"; + private const string TransmitterGroup = "Transmitter"; + private const string ExtraMessageTransmitterLineStarter = "BO_TX_BU_ "; + + private readonly string m_extraTransmitterRegex = $@"BO_TX_BU_ (?<{MessageId}>\d+)\s*:\s*(?<{TransmitterGroup}>(\s*(?:[a-zA-Z_][\w]*)\s*(?:,)?)+);"; + + private readonly IParseFailureObserver m_observer; + + public ExtraMessageTransmitterLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) + { + if (line.TrimStart().StartsWith(ExtraMessageTransmitterLineStarter) == false) + { + return false; + } + + var match = Regex.Match(line, m_extraTransmitterRegex); + if (match.Success) + { + var messageId = uint.Parse(match.Groups[MessageId].Value, CultureInfo.InvariantCulture); + var transmitters = new List(); + + foreach (var transmitter in match.Groups[TransmitterGroup].Value.Trim().Split(',')) + { + var transmitterClean = transmitter.Trim(); + if (transmitters.Contains(transmitterClean)) + { + m_observer.ExtraMessageTransmittersDuplicate(messageId, transmitterClean); + continue; + } + transmitters.Add(transmitterClean); + } + + builder.AddMessageAdditionalTransmitters(messageId, transmitters.ToArray()); + } + else + { + m_observer.ExtraMessageTransmittersSyntaxError(); + } + + return true; + } + } +}