From 6fcf8012d85d4d5439835e378597a8d87c943f19 Mon Sep 17 00:00:00 2001 From: Federico Panzani Date: Mon, 11 Sep 2023 09:28:26 +0200 Subject: [PATCH] #23 Parsing failures management (#42) * #23 Parsing failures management Added observer to listen for parsing failures. Code clean up. * #23 Added parsing failures management for each line parser Added parsing failures management for each line parser. Created silent and simple failure observer classes * #23 Added parsing failure tests Added parsing failure tests. Removed old and no more valid tests * #23 Added parsing failure observer in Demo application * #41 EnumCustomProperty parsing fails if more than one white-space character is used as separator. Updated and added some test EnumCustomProperty parsing fails if more than one white-space chracter is used as separator. Updated and added some test, code clean up. * #42 Bugfixed on NS definition Now every NS definition at the top of a file is ignored --- DbcParserLib.Tests/CommentLineParserTests.cs | 20 +- DbcParserLib.Tests/DbcBuilderTests.cs | 74 +++---- .../EnvironmentVariableLineParserTests.cs | 38 +++- DbcParserLib.Tests/MessageLineParserTests.cs | 35 +++- DbcParserLib.Tests/NodeLineParserTests.cs | 33 ++- .../PropertiesLineParserTests.cs | 191 ++++++++++++++++-- DbcParserLib.Tests/SignalLineParserTests.cs | 72 ++++++- .../SignalValueTypeLineParserTests.cs | 66 +++--- .../ValueTableLineParserTests.cs | 109 +++++++++- DbcParserLib/DbcBuilder.cs | 144 ++++++++++--- DbcParserLib/Helpers.cs | 3 +- DbcParserLib/Model/CustomProperty.cs | 6 +- .../Model/CustomPropertyDefinition.cs | 6 +- DbcParserLib/Model/Message.cs | 4 +- DbcParserLib/Model/Node.cs | 2 - DbcParserLib/Model/Signal.cs | 1 - .../Observers/IParseFailureObserver.cs | 40 ++++ .../Observers/SilentFailureObserver.cs | 135 +++++++++++++ .../Observers/SimpleFailureObserver.cs | 183 +++++++++++++++++ DbcParserLib/Parser.cs | 55 +++-- DbcParserLib/Parsers/CommentLineParser.cs | 57 ++++-- .../EnvironmentDataVariableLineParser.cs | 13 +- .../Parsers/EnvironmentVariableLineParser.cs | 11 + DbcParserLib/Parsers/IgnoreLineParser.cs | 43 +++- DbcParserLib/Parsers/MessageLineParser.cs | 14 +- DbcParserLib/Parsers/NodeLineParser.cs | 14 +- .../Parsers/PropertiesDefinitionLineParser.cs | 31 ++- DbcParserLib/Parsers/PropertiesLineParser.cs | 52 ++--- DbcParserLib/Parsers/SignalLineParser.cs | 17 +- .../Parsers/SignalValueTypeLineParser.cs | 17 +- DbcParserLib/Parsers/UnknownLineParser.cs | 10 + .../Parsers/ValueTableDefinitionLineParser.cs | 11 + DbcParserLib/Parsers/ValueTableLineParser.cs | 11 + Demo/Form1.cs | 30 ++- Demo/Program.cs | 3 - 35 files changed, 1280 insertions(+), 271 deletions(-) create mode 100644 DbcParserLib/Observers/IParseFailureObserver.cs create mode 100644 DbcParserLib/Observers/SilentFailureObserver.cs create mode 100644 DbcParserLib/Observers/SimpleFailureObserver.cs diff --git a/DbcParserLib.Tests/CommentLineParserTests.cs b/DbcParserLib.Tests/CommentLineParserTests.cs index 8133557..582df59 100644 --- a/DbcParserLib.Tests/CommentLineParserTests.cs +++ b/DbcParserLib.Tests/CommentLineParserTests.cs @@ -2,6 +2,7 @@ using DbcParserLib.Parsers; using Moq; using System.Collections.Generic; +using DbcParserLib.Observers; namespace DbcParserLib.Tests { @@ -24,7 +25,7 @@ public void Teardown() private static ILineParser CreateParser() { - return new CommentLineParser(); + return new CommentLineParser(new SilentFailureObserver()); } [Test] @@ -248,6 +249,23 @@ public void AnotherMalformedLineIsAcceptedWithoutInteraction() Assert.IsTrue(commentLineParser.TryParse(@"CM_ BU_ xxx no quotes;", dbcBuilderMock.Object, nextLineProviderMock.Object)); } + + [TestCase("CM_ SG_ 865 \"Test with incorrect \"syntax\"\";")] + [TestCase("CM_ BU_ NodeName \"Test with incorrect \"syntax\"\";")] + [TestCase("CM_ BO_ 865 \"Test with incorrect \"syntax\"\";")] + [TestCase("CM_ EV_ VarName \"Test with incorrect \"syntax\"\";")] + [TestCase("CM_ \"Test with incorrect \"syntax\"\";")] + public void CommentSyntaxErrorIsObserved(string commentLine) + { + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.CommentSyntaxError()); + + var commentParser = new CommentLineParser(observerMock.Object); + commentParser.TryParse(commentLine, dbcBuilderMock.Object, nextLineProviderMock.Object); + } } internal class ArrayBasedLineProvider : INextLineProvider diff --git a/DbcParserLib.Tests/DbcBuilderTests.cs b/DbcParserLib.Tests/DbcBuilderTests.cs index 360c32a..887922e 100644 --- a/DbcParserLib.Tests/DbcBuilderTests.cs +++ b/DbcParserLib.Tests/DbcBuilderTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using DbcParserLib.Model; +using DbcParserLib.Observers; using Moq; using NUnit.Framework; @@ -26,7 +27,7 @@ public void Teardown() [Test] public void NoInteractionProduceAnEmptyDbc() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var dbc = builder.Build(); Assert.IsEmpty(dbc.Nodes); @@ -36,7 +37,7 @@ public void NoInteractionProduceAnEmptyDbc() [Test] public void SingleNodeIsAdded() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var node = new Node { Name = "nodeName" }; builder.AddNode(node); @@ -49,7 +50,7 @@ public void SingleNodeIsAdded() [Test] public void DuplicatedNodesAreSkipped() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var node = new Node { Name = "nodeName" }; var node2 = new Node { Name = "nodeName2" }; var node3 = new Node { Name = "nodeName" }; @@ -67,7 +68,7 @@ public void DuplicatedNodesAreSkipped() [Test] public void NodeCommentIsAddedToNode() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var node = new Node { Name = "nodeName" }; builder.AddNode(node); builder.AddNodeComment("nodeName", "this is a comment"); @@ -82,7 +83,7 @@ public void NodeCommentIsAddedToNode() [Test] public void NodeCommentIsSkippedIfNodeIsNotFound() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var node = new Node { Name = "nodeName" }; builder.AddNode(node); builder.AddNodeComment("anotherNodeName", "this is a comment"); @@ -97,7 +98,7 @@ public void NodeCommentIsSkippedIfNodeIsNotFound() [Test] public void MessageIsAdded() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 1}; builder.AddMessage(message); var dbc = builder.Build(); @@ -111,7 +112,7 @@ public void MessageIsAdded() [Test] public void ExtendedMessageIsAdded() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 2147483649 }; builder.AddMessage(message); var dbc = builder.Build(); @@ -125,7 +126,7 @@ public void ExtendedMessageIsAdded() [Test] public void CommentIsAddedToMessage() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); builder.AddMessageComment(234, "comment"); @@ -140,7 +141,7 @@ public void CommentIsAddedToMessage() [Test] public void CommentIsNotAddedToMissingMessage() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); builder.AddMessageComment(235, "comment"); @@ -155,7 +156,7 @@ public void CommentIsNotAddedToMissingMessage() [Test] public void SignalIsAddedToCurrentMessage() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message1 = new Message { ID = 234 }; builder.AddMessage(message1); @@ -190,7 +191,7 @@ public void SignalIsAddedToCurrentMessage() [Test] public void SignalIsNotAddedIfNoMessageHasBeenProvidedFirst() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); builder.AddSignal(new Signal { }); var dbc = builder.Build(); @@ -201,7 +202,7 @@ public void SignalIsNotAddedIfNoMessageHasBeenProvidedFirst() [Test] public void CommentIsAddedToSignal() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -220,7 +221,7 @@ public void CommentIsAddedToSignal() [Test] public void CommentIsNotAddedToMissingSignalMessageId() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -239,7 +240,7 @@ public void CommentIsNotAddedToMissingSignalMessageId() [Test] public void CommentIsNotAddedToMissingSignalName() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -258,7 +259,7 @@ public void CommentIsNotAddedToMissingSignalName() [Test] public void TableValuesAreAddedToSignal() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -279,7 +280,7 @@ public void TableValuesAreAddedToSignal() [Test] public void TableValuesWithExtendedMessageIdAreAddedToSignal() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 2566896411 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -300,7 +301,7 @@ public void TableValuesWithExtendedMessageIdAreAddedToSignal() [Test] public void TableValueIsNotAddedToMissingSignalMessageId() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -321,7 +322,7 @@ public void TableValueIsNotAddedToMissingSignalMessageId() [Test] public void TableValueIsNotAddedToMissingSignalName() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -342,7 +343,7 @@ public void TableValueIsNotAddedToMissingSignalName() [Test] public void NamedTableValuesAreAddedToSignal() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -365,7 +366,7 @@ public void NamedTableValuesAreAddedToSignal() [Test] public void NamedTableValueIsNotAddedToMissingSignalMessageId() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -388,7 +389,7 @@ public void NamedTableValueIsNotAddedToMissingSignalMessageId() [Test] public void NamedTableValueIsNotAddedToMissingSignalName() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -411,7 +412,7 @@ public void NamedTableValueIsNotAddedToMissingSignalName() [Test] public void NamedTableValueIsNotAddedIfTableNameDoesNotExist() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 234 }; builder.AddMessage(message); var signal = new Signal { Name = "name1" }; @@ -431,7 +432,7 @@ public void NamedTableValueIsNotAddedIfTableNameDoesNotExist() public void NamedTableValueThatAreNotUsedDoNotHarmOnBuild() { var testValuesDict = new Dictionary() { { 1, "fake" } }; - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); builder.AddNamedValueTable("aTableName", testValuesDict, "1 fake"); builder.AddNamedValueTable("aTableName2", testValuesDict, "1 fake"); @@ -446,7 +447,7 @@ public void NamedTableValueThatAreNotUsedDoNotHarmOnBuild() public void NamedTablesWithSameNameAreManaged() { var testValuesDict = new Dictionary() { { 1, "fake" } }; - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); builder.AddNamedValueTable("aTableName", testValuesDict, "1 fake"); builder.AddNamedValueTable("aTableName", testValuesDict, "1 fake"); @@ -456,30 +457,5 @@ public void NamedTablesWithSameNameAreManaged() Assert.IsEmpty(dbc.Nodes); Assert.IsEmpty(dbc.Messages); } - - [Test] - public void NamedTablesWithSameNameOverridesPrevious() - { - var builder = new DbcBuilder(); - var message = new Message { ID = 234 }; - builder.AddMessage(message); - var signal = new Signal { Name = "name1" }; - builder.AddSignal(signal); - var testValuesDict = new Dictionary() { { 1, "fake1" } }; - var testValuesDict2 = new Dictionary() { { 2, "fake2" } }; - - builder.AddNamedValueTable("aTableName", testValuesDict, "1 fake1"); - builder.AddNamedValueTable("aTableName", testValuesDict2, "2 fake2"); - - builder.LinkNamedTableToSignal(234, "name1", "aTableName"); - var dbc = builder.Build(); - - Assert.IsEmpty(dbc.Nodes); - Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(234, dbc.Messages.First().ID); - Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); - Assert.AreEqual(testValuesDict2, dbc.Messages.First().Signals.First().ValueTableMap); - Assert.AreEqual("2 fake2", dbc.Messages.First().Signals.First().ValueTable); - } } } \ No newline at end of file diff --git a/DbcParserLib.Tests/EnvironmentVariableLineParserTests.cs b/DbcParserLib.Tests/EnvironmentVariableLineParserTests.cs index e5376c6..6fc1ae0 100644 --- a/DbcParserLib.Tests/EnvironmentVariableLineParserTests.cs +++ b/DbcParserLib.Tests/EnvironmentVariableLineParserTests.cs @@ -3,6 +3,7 @@ using DbcParserLib.Model; using Moq; using System.Collections.Generic; +using DbcParserLib.Observers; namespace DbcParserLib.Tests { @@ -25,9 +26,10 @@ public void Teardown() private static List CreateParser() { + var observer = new SilentFailureObserver(); return new List() { - new EnvironmentDataVariableLineParser(), - new EnvironmentVariableLineParser() + new EnvironmentDataVariableLineParser(observer), + new EnvironmentVariableLineParser(observer) }; } @@ -165,5 +167,37 @@ public void EnvironmentDataLineIsParsedTest() Assert.IsTrue(ParseLine(parsingLine, environmentVariableLineParser, dbcBuilderMock.Object, nextLineProviderMock.Object)); } + + [Test] + public void EnvironmentDataSyntaxErrorIsObserved() + { + var line = "ENVVAR_DATA_ varName : -1024;"; + + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.EnvironmentDataVariableSyntaxError()); + + var lineParser = new EnvironmentDataVariableLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); + } + + [Test] + public void EnvironmentDataNotFoundErrorIsObserved() + { + var varName = "testVar"; + uint varSize = 1024; + var line = $"ENVVAR_DATA_ {varName} : {varSize};"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.EnvironmentVariableNameNotFound(varName)); + + var lineParser = new EnvironmentDataVariableLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } } } \ No newline at end of file diff --git a/DbcParserLib.Tests/MessageLineParserTests.cs b/DbcParserLib.Tests/MessageLineParserTests.cs index 4327245..8343f39 100644 --- a/DbcParserLib.Tests/MessageLineParserTests.cs +++ b/DbcParserLib.Tests/MessageLineParserTests.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using DbcParserLib.Parsers; using DbcParserLib.Model; +using DbcParserLib.Observers; using Moq; namespace DbcParserLib.Tests @@ -23,7 +24,7 @@ public void Teardown() private static ILineParser CreateParser() { - return new MessageLineParser(); + return new MessageLineParser(new SilentFailureObserver()); } [Test] @@ -105,5 +106,37 @@ public void FullLineWithSomeRamdomSpacesIsParsed() Assert.IsTrue(messageLineParser.TryParse(@"BO_ 1041 DOORS_SEATBELTS : 8 TRX ", dbcBuilderMock.Object, nextLineProviderMock.Object)); } + + [TestCase("BO_ 123 msgName : -32 transmitter")] + [TestCase("BO_ -123 msgName : 32 transmitter")] + [TestCase("BO_ 123 0msgName : 32 transmitter")] + public void MessageSyntaxErrorIsObserved(string line) + { + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.MessageSyntaxError()); + + var lineParser = new MessageLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); + } + + [Test] + public void DuplicateMessageErrorIsObserved() + { + uint messageId = 123; + var line = $"BO_ {messageId} msgName : 32 transmitter"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.DuplicateMessage(messageId)); + + var lineParser = new MessageLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } } } \ No newline at end of file diff --git a/DbcParserLib.Tests/NodeLineParserTests.cs b/DbcParserLib.Tests/NodeLineParserTests.cs index 7754a37..9e4921d 100644 --- a/DbcParserLib.Tests/NodeLineParserTests.cs +++ b/DbcParserLib.Tests/NodeLineParserTests.cs @@ -3,6 +3,7 @@ using DbcParserLib.Model; using Moq; using System.Collections.Generic; +using DbcParserLib.Observers; namespace DbcParserLib.Tests { @@ -24,7 +25,7 @@ public void Teardown() private static ILineParser CreateParser() { - return new NodeLineParser(); + return new NodeLineParser(new SilentFailureObserver()); } [Test] @@ -91,5 +92,35 @@ public void FullLineIsParsed() Assert.IsTrue(nodeLineParser.TryParse(@"BU_: NODE_1 NODE_2 NODE_4 ", dbcBuilderMock.Object, nextLineProviderMock.Object)); CollectionAssert.AreEquivalent(expectations, results); } + + [TestCase("BU_: 0nodeName")] + [TestCase("BU_:nodeName")] + public void NodeSyntaxErrorIsObserved(string line) + { + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.NodeSyntaxError()); + + var lineParser = new NodeLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); + } + + [Test] + public void DuplicateNodeErrorIsObserved() + { + var nodeName = "testNode"; + var line = $"BU_: {nodeName} {nodeName}"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.DuplicateNode(nodeName)); + + var lineParser = new NodeLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } } } \ No newline at end of file diff --git a/DbcParserLib.Tests/PropertiesLineParserTests.cs b/DbcParserLib.Tests/PropertiesLineParserTests.cs index a554004..0fd42cd 100644 --- a/DbcParserLib.Tests/PropertiesLineParserTests.cs +++ b/DbcParserLib.Tests/PropertiesLineParserTests.cs @@ -5,6 +5,7 @@ using System.Linq; using System.IO; using System.Collections.Generic; +using DbcParserLib.Observers; namespace DbcParserLib.Tests { @@ -26,9 +27,10 @@ public void Teardown() private static List CreateParser() { + var observer = new SilentFailureObserver(); return new List() { - new PropertiesLineParser(), - new PropertiesDefinitionLineParser() + new PropertiesLineParser(observer), + new PropertiesDefinitionLineParser(observer) }; } @@ -45,7 +47,7 @@ private static bool ParseLine(string line, List lineParser, IDbcBui [Test] public void IntDefinitionCustomPropertyIsParsedTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var customPropertyLineParsers = CreateParser(); var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); @@ -56,7 +58,7 @@ public void IntDefinitionCustomPropertyIsParsedTest() [Test] public void FloatDefinitionCustomPropertyIsParsedTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var customPropertyLineParsers = CreateParser(); var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); @@ -86,7 +88,7 @@ public void ScientificNotationDefinitionCustomPropertyIsParsedTest() [Test] public void StringDefinitionCustomPropertyIsParsedTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var customPropertyLineParsers = CreateParser(); var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); @@ -97,7 +99,7 @@ public void StringDefinitionCustomPropertyIsParsedTest() [Test] public void EnumDefinitionCustomPropertyIsParsedTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var customPropertyLineParsers = CreateParser(); var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); @@ -105,10 +107,21 @@ public void EnumDefinitionCustomPropertyIsParsedTest() Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName"" ""Val2"";", customPropertyLineParsers, builder, nextLineProvider)); } + [Test] + public void EnumDefinitionCustomPropertyMoreWhiteSpaceIsParsedTest() + { + var builder = new DbcBuilder(new SilentFailureObserver()); + + var customPropertyLineParsers = CreateParser(); + var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName"" ENUM ""Val1"",""Val2"",""Val3"" ;", customPropertyLineParsers, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName"" ""Val2"";", customPropertyLineParsers, builder, nextLineProvider)); + } + [Test] public void MsgCustomPropertyIsParsedTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 2394947585 }; builder.AddMessage(message); @@ -125,7 +138,7 @@ public void MsgCustomPropertyIsParsedTest() [Test] public void SigCustomPropertyIsParsedTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var message = new Message { ID = 2394947585 }; builder.AddMessage(message); var signal = new Signal { Name = "sig_name" }; @@ -144,7 +157,7 @@ public void SigCustomPropertyIsParsedTest() [Test] public void NodeCustomPropertyIsParsedTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var node = new Node { Name = "Node1" }; builder.AddNode(node); @@ -162,7 +175,7 @@ public void NodeCustomPropertyIsParsedTest() [Test] public void NodeScientificNotationCustomPropertyIsParsedTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var node = new Node { Name = "Node1" }; builder.AddNode(node); @@ -178,7 +191,7 @@ public void NodeScientificNotationCustomPropertyIsParsedTest() [Test] public void NodeMultipleCustomPropertyAreParsedTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var node = new Node { Name = "Node1" }; builder.AddNode(node); @@ -200,7 +213,7 @@ public void NodeMultipleCustomPropertyAreParsedTest() [Test] public void CustomPropertyIsAssignedToDifferentNodesTest() { - var builder = new DbcBuilder(); + var builder = new DbcBuilder(new SilentFailureObserver()); var node1 = new Node { Name = "Node1" }; var node2 = new Node { Name = "Node2" }; builder.AddNode(node1); @@ -218,5 +231,159 @@ public void CustomPropertyIsAssignedToDifferentNodesTest() Assert.AreEqual(40, dbc.Nodes.First().CustomProperties["AttributeName"].IntegerCustomProperty.Value); Assert.AreEqual(70, dbc.Nodes.ElementAt(1).CustomProperties["AttributeName"].IntegerCustomProperty.Value); } + + [TestCase("BA_ \"attributeName\" BO_ -123 100;")] + [TestCase("BA_ \"attributeName\" SG_ 123 signalName value;")] + [TestCase("BA_ \"attributeName\" EV_ varName 1e10")] + [TestCase("BA_ attributeName BU_ nodeName 0;")] + public void PropertySyntaxErrorIsObserved(string line) + { + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.PropertySyntaxError()); + + var lineParser = new PropertiesLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); + } + + [Test] + public void CustomPropertyNotFoundErrorIsObserved() + { + var propertyName = "attributeName"; + var nodeName = "nodeName"; + var value = "100"; + var line = $"BA_ \"{propertyName}\" BU_ {nodeName} {value};"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.CustomPropertyNameNotFound(propertyName)); + + var lineParser = new PropertiesLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } + + [Test] + public void CustomPropertyNodeNotFoundErrorIsObserved() + { + var propertyName = "attributeName"; + var nodeName = "nodeName"; + var value = "100"; + + var line1 = $"BA_DEF_ BU_ \"{propertyName}\" INT 0 65535;"; + var line2 = $"BA_ \"{propertyName}\" BU_ {nodeName} {value};"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.NodeNameNotFound(nodeName)); + + ILineParser lineParser = new PropertiesDefinitionLineParser(observerMock.Object); + lineParser.TryParse(line1, dbcBuilder, nextLineProviderMock.Object); + + lineParser = new PropertiesLineParser(observerMock.Object); + lineParser.TryParse(line2, dbcBuilder, nextLineProviderMock.Object); + } + + [Test] + public void DuplicateCustomPropertyErrorIsObserved() + { + var propertyName = "attributeName"; + var nodeName = "nodeName"; + var value = "100"; + + var line1 = $"BA_DEF_ BU_ \"{propertyName}\" INT 0 65535;"; + var line2 = $"BA_ \"{propertyName}\" BU_ {nodeName} {value};"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.DuplicateCustomPropertyInNode(propertyName, nodeName)); + + dbcBuilder.AddNode(new Node() + { + Name = nodeName + }); + ILineParser lineParser = new PropertiesDefinitionLineParser(observerMock.Object); + lineParser.TryParse(line1, dbcBuilder, nextLineProviderMock.Object); + + lineParser = new PropertiesLineParser(observerMock.Object); + lineParser.TryParse(line2, dbcBuilder, nextLineProviderMock.Object); + lineParser.TryParse(line2, dbcBuilder, nextLineProviderMock.Object); + } + + [TestCase("BA_DEF_DEF_ \"attributeName\" BO_ -123 100;")] + [TestCase("BA_DEF_DEF_ \"attributeName\" SG_ 123 signalName value")] + [TestCase("BA_DEF_DEF_ \"attributeName\" EV_ 0varName 1e10;")] + [TestCase("BA_DEF_DEF_ attributeName BU_ nodeName 0;")] + public void PropertyDefaultSyntaxErrorIsObserved(string line) + { + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.PropertyDefaultSyntaxError()); + + var lineParser = new PropertiesDefinitionLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); + } + + [Test] + public void CustomPropertyDefaultNotFoundErrorIsObserved() + { + var propertyName = "attributeName"; + var line = $"BA_DEF_DEF_ \"{propertyName}\" 0;"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.CustomPropertyNameNotFound(propertyName)); + + var lineParser = new PropertiesDefinitionLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } + + [TestCase("BA_DEF_ BO_ \"GenMsgCycleTime\" INT 1.5 65535;")] + [TestCase("BA_DEF_ \"attributeName\" STRING")] + [TestCase("BA_DEF_ SGG_ \"attributeName\" FLOAT -3.4E+038 3.4E+038;")] + [TestCase("BA_DEF_ BU_ \"attributeName\" STRING 0;")] + [TestCase("BA_DEF_ attributeName STRING")] + [TestCase("BA_DEF_ BU_ \"Ciao\" ENUM \"Cyclic\"\"Event\",\"CyclicIfActive\",\"SpontanWithDelay\",\"CyclicAndSpontan\";")] + [TestCase("BA_DEF_ BU_ \"Ciao\" ENUM \"Cyclic\",\"Event\", \"CyclicIfActive\",\"SpontanWithDelay\",\"CyclicAndSpontan\";")] + public void PropertyDefinitionSyntaxErrorIsObserved(string line) + { + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.PropertyDefinitionSyntaxError()); + + var lineParser = new PropertiesDefinitionLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); + } + + [Test] + public void CustomPropertyDuplicateErrorIsObserved() + { + var propertyName = "attributeName"; + var line1 = $"BA_DEF_ BO_ \"{propertyName}\" STRING;"; + var line2 = $"BA_DEF_ BO_ \"{propertyName}\" INT 0 65535;"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.DuplicateCustomProperty(propertyName)); + + var lineParser = new PropertiesDefinitionLineParser(observerMock.Object); + lineParser.TryParse(line1, dbcBuilder, nextLineProviderMock.Object); + lineParser.TryParse(line2, dbcBuilder, nextLineProviderMock.Object); + } } } \ No newline at end of file diff --git a/DbcParserLib.Tests/SignalLineParserTests.cs b/DbcParserLib.Tests/SignalLineParserTests.cs index 874706e..55db7e0 100644 --- a/DbcParserLib.Tests/SignalLineParserTests.cs +++ b/DbcParserLib.Tests/SignalLineParserTests.cs @@ -3,6 +3,7 @@ using DbcParserLib.Model; using Moq; using System.Linq; +using DbcParserLib.Observers; namespace DbcParserLib.Tests { @@ -24,7 +25,7 @@ public void Teardown() private static ILineParser CreateParser() { - return new SignalLineParser(); + return new SignalLineParser(new SilentFailureObserver()); } [Test] @@ -47,16 +48,6 @@ public void RandomStartIsIgnored() Assert.IsFalse(signalLineParser.TryParse("CF_", dbcBuilderMock.Object, nextLineProviderMock.Object)); } - [Test] - public void OnlyPrefixIsAcceptedWithNoInteractions() - { - var dbcBuilderMock = m_repository.Create(); - var signalLineParser = CreateParser(); - var nextLineProviderMock = m_repository.Create(); - - Assert.IsTrue(signalLineParser.TryParse("SG_", dbcBuilderMock.Object, nextLineProviderMock.Object)); - } - [Test] public void OnlyPrefixWithSpacesIsAcceptedWithNoInteractions() { @@ -196,5 +187,64 @@ public void ParseSignalWithDifferentColonSpaces() Assert.AreEqual(1, dbc.Messages.Count()); Assert.AreEqual(3, dbc.Messages.SelectMany(m => m.Signals).Count()); } + + [TestCase("SG_ qGearboxOilMin : 0|16@1+ (0.1,0) [0|6553.5] \"l/min\" \"NATEC\"")] + [TestCase("SG_ qGearboxOilMin : 0|16@1+ (0.1,0) [0|6553.5] l/min NATEC")] + [TestCase("SG_ \"qGearboxOilMin\" : 0|16@1+ (0.1,0) [0|6553.5] \"l/min\" NATEC")] + [TestCase("SG_ qGearboxOilMin 0|16@1+ (0.1,0) [0|6553.5] \"l/min\" NATEC")] + [TestCase("SG_ ")] + public void SignalSyntaxErrorIsObserved(string line) + { + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.SignalSyntaxError()); + + var lineParser = new SignalLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); + } + + [Test] + public void SignalMessageNotFoundErrorIsObserved() + { + var line = "SG_ qGearboxOilMin : 0|16@1+ (0.1,0) [0|6553.5] \"l/min\" NATEC"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.NoMessageFound()); + + var lineParser = new SignalLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } + + [Test] + public void SignalDuplicateErrorIsObserved() + { + var nodeName = "nodeName"; + var signalName = "signalName"; + uint messageId = 123; + var line1 = $"BU_: {nodeName}"; + var line2 = $"BO_ {messageId} messageName: 8 {nodeName}"; + var line3 = $"SG_ {signalName} : 0|16@1+ (0.1,0) [0|6553.5] \"l/min\" {nodeName}"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.DuplicateSignalInMessage(messageId, signalName)); + + var nodeLineParser = new NodeLineParser(observerMock.Object); + nodeLineParser.TryParse(line1, dbcBuilder, nextLineProviderMock.Object); + + var messageLineParser = new MessageLineParser(observerMock.Object); + messageLineParser.TryParse(line2, dbcBuilder, nextLineProviderMock.Object); + + var signalLineParser = new SignalLineParser(observerMock.Object); + signalLineParser.TryParse(line3, dbcBuilder, nextLineProviderMock.Object); + signalLineParser.TryParse(line3, dbcBuilder, nextLineProviderMock.Object); + } } } \ No newline at end of file diff --git a/DbcParserLib.Tests/SignalValueTypeLineParserTests.cs b/DbcParserLib.Tests/SignalValueTypeLineParserTests.cs index c82f579..d4d824e 100644 --- a/DbcParserLib.Tests/SignalValueTypeLineParserTests.cs +++ b/DbcParserLib.Tests/SignalValueTypeLineParserTests.cs @@ -1,4 +1,5 @@ using DbcParserLib.Model; +using DbcParserLib.Observers; using DbcParserLib.Parsers; using Moq; using NUnit.Framework; @@ -24,7 +25,7 @@ public void Teardown() private static ILineParser CreateParser() { - return new SignalValueTypeLineParser(); + return new SignalValueTypeLineParser(new SilentFailureObserver()); } [Test] @@ -57,26 +58,6 @@ public void OnlyPrefixIsIgnored() Assert.IsFalse(signalLineParser.TryParse("SIG_VALTYPE_ ", dbcBuilderMock.Object, nextLineProviderMock.Object)); } - [Test] - public void PrefixAndMessageIsIgnored() - { - var dbcBuilderMock = m_repository.Create(); - var signalLineParser = CreateParser(); - var nextLineProviderMock = m_repository.Create(); - - Assert.IsFalse(signalLineParser.TryParse("SIG_VALTYPE_ 32 ", dbcBuilderMock.Object, nextLineProviderMock.Object)); - } - - [Test] - public void PrefixMessageAndSignalIsIgnored() - { - var dbcBuilderMock = m_repository.Create(); - var signalLineParser = CreateParser(); - var nextLineProviderMock = m_repository.Create(); - - Assert.IsFalse(signalLineParser.TryParse("SIG_VALTYPE_ 32 signal", dbcBuilderMock.Object, nextLineProviderMock.Object)); - } - [Test] public void FullLineIsParsed() { @@ -88,47 +69,62 @@ public void FullLineIsParsed() } [Test] - public void MessageMustBeANumber() + public void ValueOneCallsFloat() { var dbcBuilderMock = m_repository.Create(); var signalLineParser = CreateParser(); var nextLineProviderMock = m_repository.Create(); - Assert.IsFalse(signalLineParser.TryParse("SIG_VALTYPE_ xxx signal 0", dbcBuilderMock.Object, nextLineProviderMock.Object)); + dbcBuilderMock.Setup(x => x.AddSignalValueType(45, "signal", DbcValueType.IEEEFloat)); + + Assert.IsTrue(signalLineParser.TryParse("SIG_VALTYPE_ 45 signal 1;", dbcBuilderMock.Object, nextLineProviderMock.Object)); } [Test] - public void ValueMustBeANumber() + public void ValueTwoCallsDouble() { var dbcBuilderMock = m_repository.Create(); var signalLineParser = CreateParser(); var nextLineProviderMock = m_repository.Create(); - Assert.IsFalse(signalLineParser.TryParse("SIG_VALTYPE_ 45 signal xx", dbcBuilderMock.Object, nextLineProviderMock.Object)); + dbcBuilderMock.Setup(x => x.AddSignalValueType(45, "signal", DbcValueType.IEEEDouble)); + + Assert.IsTrue(signalLineParser.TryParse("SIG_VALTYPE_ 45 signal 2;", dbcBuilderMock.Object, nextLineProviderMock.Object)); } - [Test] - public void ValueOneCallsFloat() + [TestCase("SIG_VALTYPE_ 869 qGearboxOil 1")] + [TestCase("SIG_VALTYPE_ -869 qGearboxOil 1;")] + [TestCase("SIG_VALTYPE_ 869 \"qGearboxOil\" 1;")] + [TestCase("SIG_VALTYPE_ 869 qGearboxOil 4;")] + [TestCase("SIG_VALTYPE_ 45 signal xx;")] + [TestCase("SIG_VALTYPE_ xx signal 1;")] + public void SignalValueTypeSyntaxErrorIsObserved(string line) { + var observerMock = m_repository.Create(); var dbcBuilderMock = m_repository.Create(); - var signalLineParser = CreateParser(); var nextLineProviderMock = m_repository.Create(); - dbcBuilderMock.Setup(x => x.AddSignalValueType(45, "signal", DbcValueType.IEEEFloat)); + observerMock.Setup(o => o.SignalValueTypeSyntaxError()); - Assert.IsTrue(signalLineParser.TryParse("SIG_VALTYPE_ 45 signal 1;", dbcBuilderMock.Object, nextLineProviderMock.Object)); + var lineParser = new SignalValueTypeLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); } [Test] - public void ValueTwoCallsDouble() + public void SignalValueTypeNotFoundErrorIsObserved() { - var dbcBuilderMock = m_repository.Create(); - var signalLineParser = CreateParser(); + uint messageId = 123; + var signalName = "signalName"; + var line = $"SIG_VALTYPE_ {messageId} {signalName} : 1;"; + + var observerMock = m_repository.Create(); var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); - dbcBuilderMock.Setup(x => x.AddSignalValueType(45, "signal", DbcValueType.IEEEDouble)); + observerMock.Setup(o => o.SignalNameNotFound(messageId, signalName)); - Assert.IsTrue(signalLineParser.TryParse("SIG_VALTYPE_ 45 signal 2;", dbcBuilderMock.Object, nextLineProviderMock.Object)); + var lineParser = new SignalValueTypeLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); } } } \ No newline at end of file diff --git a/DbcParserLib.Tests/ValueTableLineParserTests.cs b/DbcParserLib.Tests/ValueTableLineParserTests.cs index f4cbac0..edad430 100644 --- a/DbcParserLib.Tests/ValueTableLineParserTests.cs +++ b/DbcParserLib.Tests/ValueTableLineParserTests.cs @@ -2,6 +2,7 @@ using DbcParserLib.Parsers; using Moq; using System.Collections.Generic; +using DbcParserLib.Observers; namespace DbcParserLib.Tests { @@ -23,9 +24,10 @@ public void Teardown() private static List CreateParser() { + var observer = new SilentFailureObserver(); return new List() { - new ValueTableDefinitionLineParser(), - new ValueTableLineParser() + new ValueTableDefinitionLineParser(observer), + new ValueTableLineParser(observer) }; } @@ -167,5 +169,108 @@ public void ValueTableWithMapDefinitionIsParsedAndLinkedToChannel() Assert.IsTrue(ParseLine(@"VAL_ 470 channelName 3 ""AEB_LOCK_STATE_SNA"" 2 ""AEB_LOCK_STATE_UNUSED"" 1 ""AEB_LOCK_STATE_UNLOCKED"" 0 ""AEB_LOCK_STATE_LOCKED"" ;", valueTableLineParsers, dbcBuilderMock.Object, nextLineProviderMock.Object)); } + + [TestCase("VAL_ 869 qGearboxOil 0 \"Running\" 1 \"Idle\" ")] + [TestCase("VAL_ 869 qGearboxOil 0 \"Running\" 1 \"Idle\";")] + [TestCase("VAL_ -869 qGearboxOil 0 \"Running\" 1 \"Idle\" ;")] + [TestCase("VAL_ 869 \"qGearboxOil\" 0 \"Running\" 1 \"Idle\" ;")] + [TestCase("VAL_ 869 qGearboxOil 0 \"Running\" 1 Idle ;")] + [TestCase("VAL_ envVarName 0 \"Running\" 1 Idle ;")] + [TestCase("VAL_ envVarName 0 \"Running\" 1 \"Idle\" ")] + [TestCase("VAL_ envVarName 0 \"Running\" 1.5 \"Idle\" ;")] + public void ValueTableSyntaxErrorIsObserved(string line) + { + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.ValueTableSyntaxError()); + + var lineParser = new ValueTableLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); + } + + [Test] + public void ValueTableNameNotFoundErrorIsObserved() + { + var tableName = "tableName"; + var line = $"VAL_ 123 signalName {tableName};"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.TableMapNameNotFound(tableName)); + + var lineParser = new ValueTableLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } + + [Test] + public void ValueTableSignalNameNotFoundErrorIsObserved() + { + uint messageId = 123; + var signalName = "signalName"; + var line = $"VAL_ {messageId} {signalName} 0 \"Running\" 1 \"Idle\" ;"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.SignalNameNotFound(messageId, signalName)); + + var lineParser = new ValueTableLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } + + [Test] + public void ValueTableEnvironmentNameNotFoundErrorIsObserved() + { + var envName = "envName"; + var line = $"VAL_ {envName} 0 \"Running\" 1 \"Idle\" ;"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.EnvironmentVariableNameNotFound(envName)); + + var lineParser = new ValueTableLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } + + [TestCase("VAL_TABLE_ tableName 0 \"Running\" 1 \"Idle\";")] + [TestCase("VAL_TABLE_ tableName 0 \"Running\" 1 \"Idle\"")] + [TestCase("VAL_TABLE_ tableName 0 \"Running\" 1 Idle;")] + [TestCase("VAL_TABLE_ \"tableName\" 0 \"Running\" 1 \"Idle\" ;")] + [TestCase("VAL_TABLE_ tableName 0 \"Running\" 1.5 \"Idle\" ;")] + public void ValueTableDefinitionSyntaxErrorIsObserved(string line) + { + var observerMock = m_repository.Create(); + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + observerMock.Setup(o => o.ValueTableDefinitionSyntaxError()); + + var lineParser = new ValueTableDefinitionLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilderMock.Object, nextLineProviderMock.Object); + } + + [Test] + public void ValueTableDefinitionDuplicateErrorIsObserved() + { + var tableName = "tableName"; + var line = $"VAL_TABLE_ {tableName} 0 \"Running\" 1 \"Idle\" ;"; + + var observerMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + var dbcBuilder = new DbcBuilder(observerMock.Object); + + observerMock.Setup(o => o.DuplicateValueTableName(tableName)); + + var lineParser = new ValueTableDefinitionLineParser(observerMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + lineParser.TryParse(line, dbcBuilder, nextLineProviderMock.Object); + } } } \ No newline at end of file diff --git a/DbcParserLib/DbcBuilder.cs b/DbcParserLib/DbcBuilder.cs index 9e83859..f008bfe 100644 --- a/DbcParserLib/DbcBuilder.cs +++ b/DbcParserLib/DbcBuilder.cs @@ -1,9 +1,7 @@ using System.Collections.Generic; -using System.Globalization; using System.Linq; -using System.Linq.Expressions; -using System.Xml.Linq; using DbcParserLib.Model; +using DbcParserLib.Observers; namespace DbcParserLib { @@ -15,6 +13,8 @@ internal class ValuesTable internal class DbcBuilder : IDbcBuilder { + private readonly IParseFailureObserver m_observer; + private readonly ISet m_nodes = new HashSet(new NodeEqualityComparer()); private readonly IDictionary m_messages = new Dictionary(); private readonly IDictionary> m_signals = new Dictionary>(); @@ -29,16 +29,32 @@ internal class DbcBuilder : IDbcBuilder private Message m_currentMessage; + public DbcBuilder(IParseFailureObserver observer) + { + m_observer = observer; + } + public void AddNode(Node node) { - m_nodes.Add(node); + if(m_nodes.Contains(node)) + m_observer.DuplicateNode(node.Name); + else + m_nodes.Add(node); } public void AddMessage(Message message) { - m_messages[message.ID] = message; - m_currentMessage = message; - m_signals[message.ID] = new Dictionary(); + if(m_messages.TryGetValue(message.ID, out var msg)) + { + m_currentMessage = msg; + m_observer.DuplicateMessage(message.ID); + } + else + { + m_messages[message.ID] = message; + m_currentMessage = message; + m_signals[message.ID] = new Dictionary(); + } } public void AddSignal(Signal signal) @@ -46,24 +62,37 @@ public void AddSignal(Signal signal) if (m_currentMessage != null) { signal.ID = m_currentMessage.ID; - m_signals[m_currentMessage.ID][signal.Name] = signal; + if(m_signals[m_currentMessage.ID].TryGetValue(signal.Name, out _)) + m_observer.DuplicateSignalInMessage(m_currentMessage.ID, signal.Name); + else + m_signals[m_currentMessage.ID][signal.Name] = signal; } + else + m_observer.NoMessageFound(); } public void AddCustomProperty(CustomPropertyObjectType objectType, CustomPropertyDefinition customProperty) { - m_customProperties[objectType][customProperty.Name] = customProperty; + if(m_customProperties[objectType].TryGetValue(customProperty.Name, out _)) + m_observer.DuplicateCustomProperty(customProperty.Name); + else + m_customProperties[objectType][customProperty.Name] = customProperty; } public void AddCustomPropertyDefaultValue(string propertyName, string value) { + var found = false; foreach(var objectType in m_customProperties.Keys) { if (m_customProperties[objectType].TryGetValue(propertyName, out var customProperty)) { customProperty.SetCustomPropertyDefaultValue(value); + found = true; } } + + if(!found) + m_observer.CustomPropertyNameNotFound(propertyName); } public void AddNodeCustomProperty(string propertyName, string nodeName, string value) @@ -75,9 +104,16 @@ public void AddNodeCustomProperty(string propertyName, string nodeName, string v { var property = new CustomProperty(customProperty); property.SetCustomPropertyValue(value); - node.CustomProperties[propertyName] = property; + if(node.CustomProperties.TryGetValue(propertyName, out _)) + m_observer.DuplicateCustomPropertyInNode(propertyName, node.Name); + else + node.CustomProperties[propertyName] = property; } + else + m_observer.NodeNameNotFound(nodeName); } + else + m_observer.CustomPropertyNameNotFound(propertyName); } public void AddEnvironmentVariableCustomProperty(string propertyName, string variableName, string value) @@ -88,9 +124,16 @@ public void AddEnvironmentVariableCustomProperty(string propertyName, string var { var property = new CustomProperty(customProperty); property.SetCustomPropertyValue(value); - envVariable.CustomProperties[propertyName] = property; + if(envVariable.CustomProperties.TryGetValue(propertyName, out _)) + m_observer.DuplicateCustomPropertyInEnvironmentVariable(propertyName, envVariable.Name); + else + envVariable.CustomProperties[propertyName] = property; } + else + m_observer.EnvironmentVariableNameNotFound(variableName); } + else + m_observer.CustomPropertyNameNotFound(propertyName); } public void AddMessageCustomProperty(string propertyName, uint messageId, string value) @@ -101,9 +144,16 @@ public void AddMessageCustomProperty(string propertyName, uint messageId, string { var property = new CustomProperty(customProperty); property.SetCustomPropertyValue(value); - message.CustomProperties[propertyName] = property; + if(message.CustomProperties.TryGetValue(propertyName, out _)) + m_observer.DuplicateCustomPropertyInMessage(propertyName, message.ID); + else + message.CustomProperties[propertyName] = property; } + else + m_observer.MessageIdNotFound(messageId); } + else + m_observer.CustomPropertyNameNotFound(propertyName); } public void AddSignalCustomProperty(string propertyName, uint messageId, string signalName, string value) @@ -114,25 +164,32 @@ public void AddSignalCustomProperty(string propertyName, uint messageId, string { var property = new CustomProperty(customProperty); property.SetCustomPropertyValue(value); - signal.CustomProperties[propertyName] = property; + if(signal.CustomProperties.TryGetValue(propertyName, out _)) + m_observer.DuplicateCustomPropertyInSignal(propertyName, signal.Name); + else + signal.CustomProperties[propertyName] = property; } + else + m_observer.SignalNameNotFound(messageId, signalName); } + else + m_observer.CustomPropertyNameNotFound(propertyName); } public void AddSignalComment(uint messageId, string signalName, string comment) { if (TryGetValueMessageSignal(messageId, signalName, out var signal)) - { signal.Comment = comment; - } + else + m_observer.SignalNameNotFound(messageId, signalName); } public void AddSignalInitialValue(uint messageId, string signalName, double initialValue) { if (TryGetValueMessageSignal(messageId, signalName, out var signal)) - { signal.InitialValue = initialValue * signal.Factor + signal.Offset; - } + else + m_observer.SignalNameNotFound(messageId, signalName); } public void AddSignalValueType(uint messageId, string signalName, DbcValueType valueType) @@ -141,36 +198,41 @@ public void AddSignalValueType(uint messageId, string signalName, DbcValueType v { signal.ValueType = valueType; } + else + m_observer.SignalNameNotFound(messageId, signalName); } public void AddNodeComment(string nodeName, string comment) { var node = m_nodes.FirstOrDefault(n => n.Name.Equals(nodeName)); if (node != null) - { node.Comment = comment; - } + else + m_observer.NodeNameNotFound(nodeName); } public void AddMessageComment(uint messageId, string comment) { if (m_messages.TryGetValue(messageId, out var message)) - { message.Comment = comment; - } + else + m_observer.MessageIdNotFound(messageId); } public void AddEnvironmentVariableComment(string variableName, string comment) { if (m_environmentVariables.TryGetValue(variableName, out var envVariable)) - { envVariable.Comment = comment; - } + else + m_observer.EnvironmentVariableNameNotFound(variableName); } public void AddEnvironmentVariable(string variableName, EnvironmentVariable environmentVariable) { - m_environmentVariables[variableName] = environmentVariable; + if(m_environmentVariables.TryGetValue(variableName, out _)) + m_observer.DuplicateEnvironmentVariableName(variableName); + else + m_environmentVariables[variableName] = environmentVariable; } public void AddEnvironmentDataVariable(string variableName, uint dataSize) @@ -183,6 +245,8 @@ public void AddEnvironmentDataVariable(string variableName, uint dataSize) Length = dataSize }; } + else + m_observer.EnvironmentVariableNameNotFound(variableName); } public void AddNodeEnvironmentVariable(string nodeName, string variableName) @@ -190,8 +254,13 @@ public void AddNodeEnvironmentVariable(string nodeName, string variableName) var node = m_nodes.FirstOrDefault(n => n.Name.Equals(nodeName)); if (node != null) { - node.EnvironmentVariables[variableName] = m_environmentVariables[variableName]; + if(node.EnvironmentVariables.TryGetValue(variableName, out _)) + m_observer.DuplicateEnvironmentVariableInNode(variableName, node.Name); + else + node.EnvironmentVariables[variableName] = m_environmentVariables[variableName]; } + else + m_observer.NodeNameNotFound(nodeName); } public void AddMessageCycleTime(uint messageId, int cycleTime) @@ -200,15 +269,22 @@ public void AddMessageCycleTime(uint messageId, int cycleTime) { message.CycleTime = cycleTime; } + else + m_observer.MessageIdNotFound(messageId); } public void AddNamedValueTable(string name, IReadOnlyDictionary dictValues, string stringValues) { - m_namedTablesMap[name] = new ValuesTable() + if(m_namedTablesMap.TryGetValue(name, out _)) + m_observer.DuplicateValueTableName(name); + else { - ValueTableMap = dictValues, - ValueTable = stringValues - }; + m_namedTablesMap[name] = new ValuesTable() + { + ValueTableMap = dictValues, + ValueTable = stringValues + }; + } } public void LinkTableValuesToSignal(uint messageId, string signalName, IReadOnlyDictionary dictValues, string stringValues) @@ -217,6 +293,8 @@ public void LinkTableValuesToSignal(uint messageId, string signalName, IReadOnly { signal.SetValueTable(dictValues, stringValues); } + else + m_observer.SignalNameNotFound(messageId, signalName); } public void LinkTableValuesToEnvironmentVariable(string variableName, IReadOnlyDictionary dictValues) @@ -225,6 +303,8 @@ public void LinkTableValuesToEnvironmentVariable(string variableName, IReadOnlyD { envVariable.ValueTableMap = dictValues; } + else + m_observer.EnvironmentVariableNameNotFound(variableName); } public void LinkNamedTableToSignal(uint messageId, string signalName, string tableName) @@ -233,6 +313,8 @@ public void LinkNamedTableToSignal(uint messageId, string signalName, string tab { LinkTableValuesToSignal(messageId, signalName, valuesTable.ValueTableMap, valuesTable.ValueTable); } + else + m_observer.TableMapNameNotFound(tableName); } private bool TryGetValueMessageSignal(uint messageId, string signalName, out Signal signal) @@ -262,7 +344,7 @@ private void FillNodesNotSetCustomPropertyWithDefault() } } - private void FillMesagesNotSetCustomPropertyWithDefault() + private void FillMessagesNotSetCustomPropertyWithDefault() { var messageCustomProperties = m_customProperties[CustomPropertyObjectType.Message]; foreach (var customProperty in messageCustomProperties) @@ -298,7 +380,7 @@ private void FillSignalsNotSetCustomPropertyWithDefault(uint messageId) public Dbc Build() { FillNodesNotSetCustomPropertyWithDefault(); - FillMesagesNotSetCustomPropertyWithDefault(); + FillMessagesNotSetCustomPropertyWithDefault(); foreach (var message in m_messages) { diff --git a/DbcParserLib/Helpers.cs b/DbcParserLib/Helpers.cs index 0b0d665..61030ea 100644 --- a/DbcParserLib/Helpers.cs +++ b/DbcParserLib/Helpers.cs @@ -1,5 +1,4 @@ -using DbcParserLib.Parsers; -using System.Text; +using System.Text; using System.Text.RegularExpressions; namespace DbcParserLib diff --git a/DbcParserLib/Model/CustomProperty.cs b/DbcParserLib/Model/CustomProperty.cs index 310eafa..b6ad352 100644 --- a/DbcParserLib/Model/CustomProperty.cs +++ b/DbcParserLib/Model/CustomProperty.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; +using System.Globalization; namespace DbcParserLib.Model { diff --git a/DbcParserLib/Model/CustomPropertyDefinition.cs b/DbcParserLib/Model/CustomPropertyDefinition.cs index ef72d8b..50421eb 100644 --- a/DbcParserLib/Model/CustomPropertyDefinition.cs +++ b/DbcParserLib/Model/CustomPropertyDefinition.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; +using System.Globalization; namespace DbcParserLib.Model { diff --git a/DbcParserLib/Model/Message.cs b/DbcParserLib/Model/Message.cs index 99babbc..8c179c5 100644 --- a/DbcParserLib/Model/Message.cs +++ b/DbcParserLib/Model/Message.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections.Generic; namespace DbcParserLib.Model { diff --git a/DbcParserLib/Model/Node.cs b/DbcParserLib/Model/Node.cs index b708081..6e70884 100644 --- a/DbcParserLib/Model/Node.cs +++ b/DbcParserLib/Model/Node.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections; using System.Collections.Generic; namespace DbcParserLib.Model diff --git a/DbcParserLib/Model/Signal.cs b/DbcParserLib/Model/Signal.cs index 74d955e..d406cb5 100644 --- a/DbcParserLib/Model/Signal.cs +++ b/DbcParserLib/Model/Signal.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; namespace DbcParserLib.Model { diff --git a/DbcParserLib/Observers/IParseFailureObserver.cs b/DbcParserLib/Observers/IParseFailureObserver.cs new file mode 100644 index 0000000..7cb4c06 --- /dev/null +++ b/DbcParserLib/Observers/IParseFailureObserver.cs @@ -0,0 +1,40 @@ +namespace DbcParserLib.Observers +{ + public interface IParseFailureObserver + { + int CurrentLine {get; set;} + + void DuplicateMessage(uint messageId); + void DuplicateNode(string nodeName); + void DuplicateSignalInMessage(uint messageId, string signalName); + void DuplicateValueTableName(string tableName); + void DuplicateEnvironmentVariableName(string variableName); + void DuplicateCustomProperty(string propertyName); + void DuplicateCustomPropertyInNode(string propertyName, string nodeName); + void DuplicateCustomPropertyInEnvironmentVariable(string propertyName, string environmentVariableName); + void DuplicateCustomPropertyInMessage(string propertyName, uint messageId); + void DuplicateCustomPropertyInSignal(string propertyName, string signalName); + void DuplicateEnvironmentVariableInNode(string environmentVariableName, string nodeName); + void CommentSyntaxError(); + void EnvironmentDataVariableSyntaxError(); + void MessageSyntaxError(); + void EnvironmentVariableSyntaxError(); + void NodeSyntaxError(); + void PropertyDefinitionSyntaxError(); + void PropertySyntaxError(); + void PropertyDefaultSyntaxError(); + void SignalSyntaxError(); + void SignalValueTypeSyntaxError(); + void ValueTableDefinitionSyntaxError(); + void ValueTableSyntaxError(); + void SignalNameNotFound(uint messageId, string signalName); + void NodeNameNotFound(string nodeName); + void MessageIdNotFound(uint messageId); + void EnvironmentVariableNameNotFound(string variableName); + void CustomPropertyNameNotFound(string propertyName); + void TableMapNameNotFound(string tableName); + void UnknownLine(); + void NoMessageFound(); + void Clear(); + } +} \ No newline at end of file diff --git a/DbcParserLib/Observers/SilentFailureObserver.cs b/DbcParserLib/Observers/SilentFailureObserver.cs new file mode 100644 index 0000000..477443b --- /dev/null +++ b/DbcParserLib/Observers/SilentFailureObserver.cs @@ -0,0 +1,135 @@ +namespace DbcParserLib.Observers +{ + public class SilentFailureObserver : IParseFailureObserver + { + public int CurrentLine {get; set;} + + public void DuplicateMessage(uint messageId) + { + } + + public void DuplicateNode(string nodeName) + { + } + + public void DuplicateSignalInMessage(uint messageId, string signalName) + { + } + + public void DuplicateValueTableName(string tableName) + { + } + + public void DuplicateEnvironmentVariableName(string variableName) + { + } + + public void DuplicateCustomProperty(string propertyName) + { + } + + public void DuplicateCustomPropertyInNode(string propertyName, string nodeName) + { + } + + public void DuplicateCustomPropertyInEnvironmentVariable(string propertyName, string environmentVariableName) + { + } + + public void DuplicateCustomPropertyInMessage(string propertyName, uint messageId) + { + } + + public void DuplicateCustomPropertyInSignal(string propertyName, string signalName) + { + } + + public void DuplicateEnvironmentVariableInNode(string environmentVariableName, string nodeName) + { + } + + public void CommentSyntaxError() + { + } + + public void EnvironmentDataVariableSyntaxError() + { + } + + public void MessageSyntaxError() + { + } + + public void EnvironmentVariableSyntaxError() + { + } + + public void NodeSyntaxError() + { + } + + public void PropertyDefinitionSyntaxError() + { + } + + public void PropertySyntaxError() + { + } + + public void PropertyDefaultSyntaxError() + { + } + + public void SignalSyntaxError() + { + } + + public void SignalValueTypeSyntaxError() + { + } + + public void ValueTableDefinitionSyntaxError() + { + } + + public void ValueTableSyntaxError() + { + } + + public void SignalNameNotFound(uint messageId, string signalName) + { + } + + public void NodeNameNotFound(string nodeName) + { + } + + public void MessageIdNotFound(uint messageId) + { + } + + public void EnvironmentVariableNameNotFound(string variableName) + { + } + + public void CustomPropertyNameNotFound(string propertyName) + { + } + + public void TableMapNameNotFound(string tableName) + { + } + + public void UnknownLine() + { + } + + public void NoMessageFound() + { + } + + public void Clear() + { + } + } +} \ No newline at end of file diff --git a/DbcParserLib/Observers/SimpleFailureObserver.cs b/DbcParserLib/Observers/SimpleFailureObserver.cs new file mode 100644 index 0000000..e0f274b --- /dev/null +++ b/DbcParserLib/Observers/SimpleFailureObserver.cs @@ -0,0 +1,183 @@ +using System.Collections.Generic; + +namespace DbcParserLib.Observers +{ + public class SimpleFailureObserver : IParseFailureObserver + + { + private readonly IList m_errors = new List(); + + public int CurrentLine {get; set;} + + private void AddError(string error) + { + m_errors.Add($"{error} at line {CurrentLine}"); + } + + public void DuplicateMessage(uint messageId) + { + AddError($"Duplicated message (ID {messageId})"); + } + + public void DuplicateNode(string nodeName) + { + AddError($"Duplicated node '{nodeName}'"); + } + + public void DuplicateSignalInMessage(uint messageId, string signalName) + { + AddError($"Duplicated signal '{signalName}' in message (ID {messageId})"); + } + + public void DuplicateValueTableName(string tableName) + { + AddError($"Duplicated value table '{tableName}'"); + } + + public void DuplicateEnvironmentVariableName(string variableName) + { + AddError($"Duplicated environment variable '{variableName}'"); + } + + public void DuplicateCustomProperty(string propertyName) + { + AddError($"Duplicated custom property '{propertyName}'"); + } + + public void DuplicateCustomPropertyInNode(string propertyName, string nodeName) + { + AddError($"Duplicated custom property '{propertyName}' in node '{nodeName}'"); + } + + public void DuplicateCustomPropertyInEnvironmentVariable(string propertyName, string environmentVariableName) + { + AddError($"Duplicated custom property '{propertyName}' in environment variable '{environmentVariableName}'"); + } + + public void DuplicateCustomPropertyInMessage(string propertyName, uint messageId) + { + AddError($"Duplicated custom property '{propertyName}' in message (ID {messageId})"); + } + + public void DuplicateCustomPropertyInSignal(string propertyName, string signalName) + { + AddError($"Duplicated custom property '{propertyName}' in signal '{signalName}'"); + } + + public void DuplicateEnvironmentVariableInNode(string environmentVariableName, string nodeName) + { + AddError($"Duplicated environment variable '{environmentVariableName}' in node '{nodeName}'"); + } + + public void CommentSyntaxError() + { + AddError("[CM_] Comment syntax error"); + } + + public void EnvironmentDataVariableSyntaxError() + { + AddError("[ENVVAR_DATA_] Environment data variable syntax error"); + } + + public void MessageSyntaxError() + { + AddError("[BO_] Message syntax error"); + } + + public void EnvironmentVariableSyntaxError() + { + AddError("[EV_] Environment variable syntax error"); + } + + public void NodeSyntaxError() + { + AddError("[BU_] Node syntax error"); + } + + public void PropertyDefinitionSyntaxError() + { + AddError("[BA_DEF_] Property definition syntax error"); + } + + public void PropertySyntaxError() + { + AddError("[BA_] Property syntax error"); + } + + public void PropertyDefaultSyntaxError() + { + AddError("[BA_DEF_DEF_] Property default value syntax error"); + } + + public void SignalSyntaxError() + { + AddError("[SG_] Signal syntax error"); + } + + public void SignalValueTypeSyntaxError() + { + AddError("[SIG_VALTYPE_] Signal value type syntax error"); + } + + public void ValueTableDefinitionSyntaxError() + { + AddError("[VAL_TABLE_] Value table definition syntax error"); + } + + public void ValueTableSyntaxError() + { + AddError("[VAL_] Value table syntax error"); + } + + public void SignalNameNotFound(uint messageId, string signalName) + { + AddError($"Signal '{signalName}' in message (ID {messageId}) not found"); + } + + public void NodeNameNotFound(string nodeName) + { + AddError($"Node '{nodeName}' not found"); + } + + public void MessageIdNotFound(uint messageId) + { + AddError($"Message (ID {messageId}) not found"); + } + + public void EnvironmentVariableNameNotFound(string variableName) + { + AddError($"Environment variable '{variableName}' not found"); + } + + public void CustomPropertyNameNotFound(string propertyName) + { + AddError($"Custom property '{propertyName}' not found"); + } + + public void TableMapNameNotFound(string tableName) + { + AddError($"Table map '{tableName}' not found"); + } + + public void UnknownLine() + { + AddError("Unknown syntax"); + } + + public void NoMessageFound() + { + AddError("No message has been defined yet"); + } + + public void Clear() + { + CurrentLine = 0; + m_errors.Clear(); + } + + public IList GetErrorList() + { + return m_errors; + } + } +} \ No newline at end of file diff --git a/DbcParserLib/Parser.cs b/DbcParserLib/Parser.cs index 313abaa..f4ec32b 100644 --- a/DbcParserLib/Parser.cs +++ b/DbcParserLib/Parser.cs @@ -1,30 +1,40 @@ using System.IO; using System.Collections.Generic; using DbcParserLib.Parsers; -using System.Reflection; -using System.Xml; +using DbcParserLib.Observers; namespace DbcParserLib { public static class Parser { - private static IEnumerable LineParsers = new List() + private static IParseFailureObserver m_parseObserver = new SilentFailureObserver(); + private static IEnumerable LineParsers = new List(); + + private static void CreateLineParsers() + { + LineParsers = new List() + { + new IgnoreLineParser(m_parseObserver), // Used to skip line we know we want to skip + new NodeLineParser(m_parseObserver), + new MessageLineParser(m_parseObserver), + new CommentLineParser(m_parseObserver), + new SignalLineParser(m_parseObserver), + new SignalValueTypeLineParser(m_parseObserver), + new ValueTableDefinitionLineParser(m_parseObserver), + new ValueTableLineParser(m_parseObserver), + new PropertiesDefinitionLineParser(m_parseObserver), + new PropertiesLineParser(m_parseObserver), + new EnvironmentVariableLineParser(m_parseObserver), + new EnvironmentDataVariableLineParser(m_parseObserver), + new UnknownLineParser(m_parseObserver) // Used as a catch all + }; + } + + public static void SetParsingFailuresObserver(IParseFailureObserver observer) { - new IgnoreLineParser(), // Used to skip line we know we want to skip - new NodeLineParser(), - new MessageLineParser(), - new CommentLineParser(), - new SignalLineParser(), - new SignalValueTypeLineParser(), - new ValueTableDefinitionLineParser(), - new ValueTableLineParser(), - new PropertiesDefinitionLineParser(), - new PropertiesLineParser(), - new EnvironmentVariableLineParser(), - new EnvironmentDataVariableLineParser(), - new UnknownLineParser() // Used as a catch all - }; - + m_parseObserver = observer; + } + public static Dbc ParseFromPath(string dbcPath) { using (var fileStream = new FileStream(dbcPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) @@ -51,7 +61,10 @@ public static Dbc Parse(string dbcText) private static Dbc ParseFromReader(TextReader reader) { - var builder = new DbcBuilder(); + CreateLineParsers(); + m_parseObserver.Clear(); + + var builder = new DbcBuilder(m_parseObserver); var nextLineProvider = new NextLineProvider(reader); while (reader.Peek() >= 0) @@ -62,10 +75,10 @@ private static Dbc ParseFromReader(TextReader reader) private static void ParseLine(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { - if(string.IsNullOrWhiteSpace(line)) + m_parseObserver.CurrentLine++; + if (string.IsNullOrWhiteSpace(line)) return; - foreach(var parser in LineParsers) { if(parser.TryParse(line, builder, nextLineProvider)) diff --git a/DbcParserLib/Parsers/CommentLineParser.cs b/DbcParserLib/Parsers/CommentLineParser.cs index acb925c..ba1c2cb 100644 --- a/DbcParserLib/Parsers/CommentLineParser.cs +++ b/DbcParserLib/Parsers/CommentLineParser.cs @@ -1,19 +1,25 @@ -using System; -using System.ComponentModel; -using System.Linq; using System.Text; using System.Text.RegularExpressions; +using DbcParserLib.Observers; namespace DbcParserLib.Parsers { internal class CommentLineParser : ILineParser { private const string CommentLineStarter = "CM_ "; + private const string GenericCommentParsingRegex = @"CM_\s+""*([^""]*)""*\s*;"; private const string NodeParsingRegex = @"CM_ BU_\s+([a-zA-Z_][\w]*)\s+""*([^""]*)""*\s*;"; private const string MessageParsingRegex = @"CM_ BO_\s+(\d+)\s+""*([^""]*)""*\s*;"; private const string SignalParsingRegex = @"CM_ SG_\s+(\d+)\s+([a-zA-Z_][\w]*)\s+""*([^""]*)""*\s*;"; private const string EnvironmentVariableParsingRegex = @"CM_ EV_\s+([a-zA-Z_][\w]*)\s+""*([^""]*)""*\s*;"; + private readonly IParseFailureObserver m_observer; + + public CommentLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { var cleanLine = line.Trim(); @@ -22,81 +28,88 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin return false; if (!cleanLine.EndsWith(";")) - cleanLine = GetNextLines(cleanLine, nextLineProvider); + cleanLine = GetNextLines(cleanLine, m_observer, nextLineProvider); if (cleanLine.StartsWith("CM_ SG_")) { - SetSignalComment(cleanLine, builder, nextLineProvider); + SetSignalComment(cleanLine, m_observer, builder, nextLineProvider); return true; } if (cleanLine.StartsWith("CM_ BU_")) { - SetNodeComment(cleanLine, builder, nextLineProvider); + SetNodeComment(cleanLine, m_observer, builder, nextLineProvider); return true; } if (cleanLine.StartsWith("CM_ BO_")) { - SetMessageComment(cleanLine, builder, nextLineProvider); + SetMessageComment(cleanLine, m_observer, builder, nextLineProvider); return true; } if (cleanLine.StartsWith("CM_ EV_")) { - SetEnvironmentVariableComment(cleanLine, builder); + SetEnvironmentVariableComment(cleanLine, m_observer, builder); return true; } - return false; + + var match = Regex.Match(cleanLine, GenericCommentParsingRegex); + if (match.Success) + return true; + + m_observer.CommentSyntaxError(); + return true; } - private static void SetSignalComment(string sigCommentStr, IDbcBuilder builder, INextLineProvider nextLineProvider) + private static void SetSignalComment(string sigCommentStr, IParseFailureObserver observer, IDbcBuilder builder, INextLineProvider nextLineProvider) { var match = Regex.Match(sigCommentStr, SignalParsingRegex); if (match.Success) - { builder.AddSignalComment(uint.Parse(match.Groups[1].Value), match.Groups[2].Value, match.Groups[3].Value); - } + else + observer.CommentSyntaxError(); } - private static void SetNodeComment(string sigCommentStr, IDbcBuilder builder, INextLineProvider nextLineProvider) + private static void SetNodeComment(string sigCommentStr, IParseFailureObserver observer, IDbcBuilder builder, INextLineProvider nextLineProvider) { var match = Regex.Match(sigCommentStr, NodeParsingRegex); if (match.Success) - { builder.AddNodeComment(match.Groups[1].Value, match.Groups[2].Value); - } + else + observer.CommentSyntaxError(); } - private static void SetMessageComment(string sigCommentStr, IDbcBuilder builder, INextLineProvider nextLineProvider) + private static void SetMessageComment(string sigCommentStr, IParseFailureObserver observer, IDbcBuilder builder, INextLineProvider nextLineProvider) { var match = Regex.Match(sigCommentStr, MessageParsingRegex); if (match.Success) - { builder.AddMessageComment(uint.Parse(match.Groups[1].Value), match.Groups[2].Value); - } + else + observer.CommentSyntaxError(); } - private static void SetEnvironmentVariableComment(string envCommentStr, IDbcBuilder builder) + private static void SetEnvironmentVariableComment(string envCommentStr, IParseFailureObserver observer, IDbcBuilder builder) { var match = Regex.Match(envCommentStr, EnvironmentVariableParsingRegex); if (match.Success) - { builder.AddEnvironmentVariableComment(match.Groups[1].Value, match.Groups[2].Value); - } + else + observer.CommentSyntaxError(); } - private static string GetNextLines(string currentLine, INextLineProvider nextLineProvider) + private static string GetNextLines(string currentLine, IParseFailureObserver observer, INextLineProvider nextLineProvider) { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine(currentLine); while (nextLineProvider.TryGetLine(out var nextLine)) { + observer.CurrentLine++; stringBuilder.AppendLine(nextLine); if (nextLine.EndsWith(";")) break; diff --git a/DbcParserLib/Parsers/EnvironmentDataVariableLineParser.cs b/DbcParserLib/Parsers/EnvironmentDataVariableLineParser.cs index 4adf34a..7acd8b9 100644 --- a/DbcParserLib/Parsers/EnvironmentDataVariableLineParser.cs +++ b/DbcParserLib/Parsers/EnvironmentDataVariableLineParser.cs @@ -1,4 +1,5 @@ using System.Text.RegularExpressions; +using DbcParserLib.Observers; namespace DbcParserLib.Parsers { @@ -7,6 +8,13 @@ internal class EnvironmentDataVariableLineParser : ILineParser private const string EnvironmentDataVariableLineStarter = "ENVVAR_DATA_ "; private const string EnvironmentDataVariableParsingRegex = @"ENVVAR_DATA_\s+([a-zA-Z_][\w]*)\s*:\s+(\d+)\s*;"; + private readonly IParseFailureObserver m_observer; + + public EnvironmentDataVariableLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { var cleanLine = line.Trim(' '); @@ -16,9 +24,10 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin var match = Regex.Match(cleanLine, EnvironmentDataVariableParsingRegex); if (match.Success) - { builder.AddEnvironmentDataVariable(match.Groups[1].Value, uint.Parse(match.Groups[2].Value)); - } + else + m_observer.EnvironmentDataVariableSyntaxError(); + return true; } } diff --git a/DbcParserLib/Parsers/EnvironmentVariableLineParser.cs b/DbcParserLib/Parsers/EnvironmentVariableLineParser.cs index d2e52bb..825e612 100644 --- a/DbcParserLib/Parsers/EnvironmentVariableLineParser.cs +++ b/DbcParserLib/Parsers/EnvironmentVariableLineParser.cs @@ -1,4 +1,5 @@ using DbcParserLib.Model; +using DbcParserLib.Observers; using System.Text.RegularExpressions; namespace DbcParserLib.Parsers @@ -8,6 +9,13 @@ internal class EnvironmentVariableLineParser : ILineParser private const string EnvironmentVariableLineStarter = "EV_ "; private const string EnvironmentVariableParsingRegex = @"EV_\s+([a-zA-Z_][\w]*)\s*:\s+([012])\s+\[([\d\+\-eE.]+)\|([\d\+\-eE.]+)\]\s+""([^""]*)""\s+([\d\+\-eE.]+)\s+(\d+)\s+DUMMY_NODE_VECTOR(800){0,1}([0123])\s+((?:[a-zA-Z_][\w]*)(?:,[a-zA-Z_][\w]*)*)\s*;"; + private readonly IParseFailureObserver m_observer; + + public EnvironmentVariableLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { var cleanLine = line.Trim(' '); @@ -80,6 +88,9 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin builder.AddNodeEnvironmentVariable(node, match.Groups[1].Value); } } + else + m_observer.EnvironmentVariableSyntaxError(); + return true; } } diff --git a/DbcParserLib/Parsers/IgnoreLineParser.cs b/DbcParserLib/Parsers/IgnoreLineParser.cs index 859b5b9..a4e25e1 100644 --- a/DbcParserLib/Parsers/IgnoreLineParser.cs +++ b/DbcParserLib/Parsers/IgnoreLineParser.cs @@ -1,12 +1,49 @@ +using DbcParserLib.Observers; + namespace DbcParserLib.Parsers { internal class IgnoreLineParser : ILineParser { + private readonly IParseFailureObserver m_observer; + + public IgnoreLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { - return line.TrimStart().StartsWith("BS_ ") || - line.TrimStart().StartsWith("NS_ ") || - line.TrimStart().StartsWith("VERSION"); + return line.TrimStart().StartsWith("VERSION") || + line.TrimStart().StartsWith("BS_") || + line.TrimStart().StartsWith("NS_ ") || + line.TrimStart().StartsWith("NS_DESC_") || + line.Trim().Equals("CM_") || + line.Trim().Equals("BA_DEF_") || + line.Trim().Equals("BA_") || + line.Trim().Equals("VAL_") || + line.Trim().Equals("CAT_DEF_") || + line.Trim().Equals("CAT_") || + line.Trim().Equals("FILTER") || + line.Trim().Equals("BA_DEF_DEF_") || + line.Trim().Equals("EV_DATA_") || + line.Trim().Equals("ENVVAR_DATA_") || + line.Trim().Equals("SGTYPE_") || + line.Trim().Equals("SGTYPE_VAL_") || + line.Trim().Equals("BA_DEF_SGTYPE_") || + line.Trim().Equals("BA_SGTYPE_") || + line.Trim().Equals("SIG_TYPE_REF_") || + line.Trim().Equals("VAL_TABLE_") || + line.Trim().Equals("SIG_GROUP_") || + line.Trim().Equals("SIG_VALTYPE_") || + line.Trim().Equals("SIGTYPE_VALTYPE_") || + line.Trim().Equals("BO_TX_BU_") || + line.Trim().Equals("BA_DEF_REL_") || + line.Trim().Equals("BA_REL_") || + line.Trim().Equals("BA_DEF_DEF_REL_") || + line.Trim().Equals("BU_SG_REL_") || + line.Trim().Equals("BU_EV_REL_") || + line.Trim().Equals("BU_BO_REL_") || + line.Trim().Equals("SG_MUL_VAL_"); } } } \ No newline at end of file diff --git a/DbcParserLib/Parsers/MessageLineParser.cs b/DbcParserLib/Parsers/MessageLineParser.cs index 62de1e5..48712f4 100644 --- a/DbcParserLib/Parsers/MessageLineParser.cs +++ b/DbcParserLib/Parsers/MessageLineParser.cs @@ -1,13 +1,21 @@ using System.Globalization; using System.Text.RegularExpressions; using DbcParserLib.Model; +using DbcParserLib.Observers; namespace DbcParserLib.Parsers { internal class MessageLineParser : ILineParser { private const string MessageLineStarter = "BO_ "; - private const string MessageRegex = @"BO_ (\d+)\s+(\w+)\s*:\s*(\d+)\s+(\w+)"; + private const string MessageRegex = @"BO_ (\d+)\s+([a-zA-Z_][\w]*)\s*:\s*(\d+)\s+([a-zA-Z_][\w]*)"; + + private readonly IParseFailureObserver m_observer; + + public MessageLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { @@ -27,7 +35,9 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin builder.AddMessage(msg); } - + else + m_observer.MessageSyntaxError(); + return true; } } diff --git a/DbcParserLib/Parsers/NodeLineParser.cs b/DbcParserLib/Parsers/NodeLineParser.cs index f5ec46c..6cceca2 100644 --- a/DbcParserLib/Parsers/NodeLineParser.cs +++ b/DbcParserLib/Parsers/NodeLineParser.cs @@ -1,13 +1,20 @@ -using System.Linq; using System.Text.RegularExpressions; using DbcParserLib.Model; +using DbcParserLib.Observers; namespace DbcParserLib.Parsers { internal class NodeLineParser : ILineParser { private const string NodeLineStarter = "BU_:"; - private const string NodeLineParsingRegex = @"BU_:((?:\s+(?:[a-zA-Z_][\w]*))*)"; + private const string NodeLineParsingRegex = @"BU_:((?:\s+(?:[a-zA-Z_][\w]*))+)"; + + private readonly IParseFailureObserver m_observer; + + public NodeLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { @@ -26,6 +33,9 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin builder.AddNode(node); } } + else + m_observer.NodeSyntaxError(); + return true; } } diff --git a/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs b/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs index 4813534..a4d5627 100644 --- a/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs +++ b/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs @@ -1,8 +1,6 @@ using DbcParserLib.Model; -using System; -using System.Collections.Generic; +using DbcParserLib.Observers; using System.Globalization; -using System.Linq; using System.Text.RegularExpressions; namespace DbcParserLib.Parsers @@ -11,9 +9,16 @@ internal class PropertiesDefinitionLineParser : ILineParser { private const string PropertiesDefinitionLineStarter = "BA_DEF_ "; private const string PropertiesDefinitionDefaultLineStarter = "BA_DEF_DEF_ "; - private const string PropertyDefinitionParsingRegex = @"BA_DEF_\s+(?:(BU_|BO_|SG_|EV_)\s+)?""([a-zA-Z_][\w]*)""\s+(?:(?:(INT|HEX)\s+(-?\d+)\s+(-?\d+))|(?:(FLOAT)\s+([\d\+\-eE.]+)\s+([\d\+\-eE.]+))|(STRING)|(ENUM\s+(?:""[^""]*"",*)*))\s*;"; + private const string PropertyDefinitionParsingRegex = @"BA_DEF_\s+(BU_|BO_|SG_|EV_)\s+""([a-zA-Z_][\w]*)""\s+(?:(?:(INT|HEX)\s+(-?\d+)\s+(-?\d+))|(?:(FLOAT)\s+([\d\+\-eE.]+)\s+([\d\+\-eE.]+))|(STRING)|(?:(ENUM)\s+((?:""[^""]*"",+)*(""[^""]*""))))\s*;"; private const string PropertyDefinitionDefaultParsingRegex = @"BA_DEF_DEF_\s+""([a-zA-Z_][\w]*)""\s+(-?\d+|[\d\+\-eE.]+|""[^""]*"")\s*;"; - + + private readonly IParseFailureObserver m_observer; + + public PropertiesDefinitionLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { var cleanLine = line.Trim(' '); @@ -26,9 +31,9 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin { var match = Regex.Match(cleanLine, PropertyDefinitionDefaultParsingRegex); if (match.Success) - { builder.AddCustomPropertyDefaultValue(match.Groups[1].Value, match.Groups[2].Value.Replace("\"", "")); - } + else + m_observer.PropertyDefaultSyntaxError(); return true; } @@ -85,21 +90,25 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin dataType = CustomPropertyDataType.String; customProperty.StringCustomProperty = new StringCustomPropertyDefinition(); } - else if (match.Groups[10].Value.StartsWith("ENUM ")) + else if (match.Groups[10].Value.StartsWith("ENUM")) { dataType = CustomPropertyDataType.Enum; - var enumDefinition = match.Groups[10].Value.Replace("\"", "").Split(' ')[1]; + var enumDefinition = match.Groups[11].Value + match.Groups[12].Value; customProperty.EnumCustomProperty = new EnumCustomPropertyDefinition { - Values = enumDefinition.Split(','), + Values = enumDefinition.Replace("\"", "").Split(',') }; } customProperty.DataType = dataType; builder.AddCustomProperty(objectType, customProperty); } + else + m_observer.PropertyDefinitionSyntaxError(); + return true; } - return false; + + return true; } } } \ No newline at end of file diff --git a/DbcParserLib/Parsers/PropertiesLineParser.cs b/DbcParserLib/Parsers/PropertiesLineParser.cs index 35cfc63..b4a47dd 100644 --- a/DbcParserLib/Parsers/PropertiesLineParser.cs +++ b/DbcParserLib/Parsers/PropertiesLineParser.cs @@ -1,8 +1,6 @@ -using DbcParserLib.Model; -using System; using System.Globalization; -using System.Linq; using System.Text.RegularExpressions; +using DbcParserLib.Observers; namespace DbcParserLib.Parsers { @@ -11,6 +9,13 @@ internal class PropertiesLineParser : ILineParser private const string PropertiesLineStarter = "BA_ "; private const string PropertyParsingRegex = @"BA_\s+""([a-zA-Z_][\w]*)""(?:\s+(?:(BU_|EV_)\s+([a-zA-Z_][\w]*))|\s+(?:(BO_)\s+(\d+))|\s+(?:(SG_)\s+(\d+)\s+([a-zA-Z_][\w]*)))?\s+(-?\d+|[\d\+\-eE.]+|""[^""]*"");"; + private readonly IParseFailureObserver m_observer; + + public PropertiesLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { var cleanLine = line.Trim(' '); @@ -18,31 +23,30 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (cleanLine.StartsWith(PropertiesLineStarter) == false) return false; - if (cleanLine.StartsWith(PropertiesLineStarter)) + var match = Regex.Match(cleanLine, PropertyParsingRegex); + if (match.Success) { - var match = Regex.Match(cleanLine, PropertyParsingRegex); - if (match.Success) + if (match.Groups[2].Value == "BU_") + builder.AddNodeCustomProperty(match.Groups[1].Value, match.Groups[3].Value, match.Groups[9].Value.Replace("\"", "")); + else if (match.Groups[2].Value == "EV_") + builder.AddEnvironmentVariableCustomProperty(match.Groups[1].Value, match.Groups[3].Value, match.Groups[9].Value.Replace("\"", "")); + else if (match.Groups[4].Value == "BO_") { - if (match.Groups[2].Value == "BU_") - builder.AddNodeCustomProperty(match.Groups[1].Value, match.Groups[3].Value, match.Groups[9].Value.Replace("\"", "")); - else if (match.Groups[2].Value == "EV_") - builder.AddEnvironmentVariableCustomProperty(match.Groups[1].Value, match.Groups[3].Value, match.Groups[9].Value.Replace("\"", "")); - else if (match.Groups[4].Value == "BO_") - { - builder.AddMessageCustomProperty(match.Groups[1].Value, uint.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), match.Groups[9].Value.Replace("\"", "")); - if (match.Groups[1].Value == "GenMsgCycleTime") - builder.AddMessageCycleTime(uint.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), int.Parse(match.Groups[9].Value, CultureInfo.InvariantCulture)); - } - else if (match.Groups[6].Value == "SG_") - { - builder.AddSignalCustomProperty(match.Groups[1].Value, uint.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), match.Groups[8].Value, match.Groups[9].Value.Replace("\"", "")); - if (match.Groups[1].Value == "GenSigStartValue") - builder.AddSignalInitialValue(uint.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), match.Groups[8].Value, double.Parse(match.Groups[9].Value, CultureInfo.InvariantCulture)); - } + builder.AddMessageCustomProperty(match.Groups[1].Value, uint.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), match.Groups[9].Value.Replace("\"", "")); + if (match.Groups[1].Value == "GenMsgCycleTime") + builder.AddMessageCycleTime(uint.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), int.Parse(match.Groups[9].Value, CultureInfo.InvariantCulture)); + } + else if (match.Groups[6].Value == "SG_") + { + builder.AddSignalCustomProperty(match.Groups[1].Value, uint.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), match.Groups[8].Value, match.Groups[9].Value.Replace("\"", "")); + if (match.Groups[1].Value == "GenSigStartValue") + builder.AddSignalInitialValue(uint.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), match.Groups[8].Value, double.Parse(match.Groups[9].Value, CultureInfo.InvariantCulture)); } - return true; } - return false; + else + m_observer.PropertySyntaxError(); + + return true; } } } \ No newline at end of file diff --git a/DbcParserLib/Parsers/SignalLineParser.cs b/DbcParserLib/Parsers/SignalLineParser.cs index 99614e3..a9b3d32 100644 --- a/DbcParserLib/Parsers/SignalLineParser.cs +++ b/DbcParserLib/Parsers/SignalLineParser.cs @@ -1,20 +1,25 @@ using System; -using System.Linq; using System.Text.RegularExpressions; using System.Globalization; using DbcParserLib.Model; +using DbcParserLib.Observers; namespace DbcParserLib.Parsers { internal class SignalLineParser : ILineParser { - private delegate void ParsingStrategy(string line, IDbcBuilder builder); - - private const string SignalLineStarter = "SG_"; + private const string SignalLineStarter = "SG_ "; private const string SignedSymbol = "-"; private static readonly string[] m_commaSpaceSeparator = new string[] { Helpers.Space, Helpers.Comma }; private const string SignalRegex = @"\s*SG_\s+([\w]+)\s*([Mm\d]*)\s*:\s*(\d+)\|(\d+)@([01])([+-])\s+\(([\d\+\-eE.]+),([\d\+\-eE.]+)\)\s+\[([\d\+\-eE.]+)\|([\d\+\-eE.]+)\]\s+""(.*)""\s+([\w\s,]+)"; - + + private readonly IParseFailureObserver m_observer; + + public SignalLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { if (line.TrimStart().StartsWith(SignalLineStarter) == false) @@ -43,6 +48,8 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin builder.AddSignal(sig); } + else + m_observer.SignalSyntaxError(); return true; } diff --git a/DbcParserLib/Parsers/SignalValueTypeLineParser.cs b/DbcParserLib/Parsers/SignalValueTypeLineParser.cs index 9aabb62..bdac460 100644 --- a/DbcParserLib/Parsers/SignalValueTypeLineParser.cs +++ b/DbcParserLib/Parsers/SignalValueTypeLineParser.cs @@ -1,13 +1,20 @@ -using System.Linq; using System.Text.RegularExpressions; using DbcParserLib.Model; +using DbcParserLib.Observers; namespace DbcParserLib.Parsers { internal class SignalValueTypeLineParser : ILineParser { private const string SignalValueTypeStarter = "SIG_VALTYPE_ "; - private const string SignalValueTypeParsingRegex = @"SIG_VALTYPE_\s+(\d+)\s+([a-zA-Z_][\w]*)\s+([0123])\s*;"; + private const string SignalValueTypeParsingRegex = @"SIG_VALTYPE_\s+(\d+)\s+([a-zA-Z_][\w]*)\s+[:]*\s*([0123])\s*;"; + + private readonly IParseFailureObserver m_observer; + + public SignalValueTypeLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { @@ -25,9 +32,11 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin builder.AddSignalValueType(uint.Parse(match.Groups[1].Value), match.Groups[2].Value, valueType == 1 ? DbcValueType.IEEEFloat : DbcValueType.IEEEDouble); } - return true; } - return false; + else + m_observer.SignalValueTypeSyntaxError(); + + return true; } } } \ No newline at end of file diff --git a/DbcParserLib/Parsers/UnknownLineParser.cs b/DbcParserLib/Parsers/UnknownLineParser.cs index 636b263..211bb43 100644 --- a/DbcParserLib/Parsers/UnknownLineParser.cs +++ b/DbcParserLib/Parsers/UnknownLineParser.cs @@ -1,10 +1,20 @@ +using DbcParserLib.Observers; + namespace DbcParserLib.Parsers { internal class UnknownLineParser : ILineParser { + private readonly IParseFailureObserver m_observer; + + public UnknownLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { // Throw or log or add a specific entry in builder maybe? + m_observer.UnknownLine(); return true; } } diff --git a/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs b/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs index d6ccd2e..90f621a 100644 --- a/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs +++ b/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs @@ -1,5 +1,6 @@ using System; using System.Text.RegularExpressions; +using DbcParserLib.Observers; namespace DbcParserLib.Parsers { @@ -8,6 +9,13 @@ internal class ValueTableDefinitionLineParser : ILineParser private const string ValueTableDefinitionLineStarter = "VAL_TABLE_ "; private const string ValueTableDefinitionParsingRegex = @"VAL_TABLE_\s+([a-zA-Z_][\w]*)\s+((?:\d+\s+(?:""[^""]*"")\s+)*)\s*;"; + private readonly IParseFailureObserver m_observer; + + public ValueTableDefinitionLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { var cleanLine = line.Trim(' '); @@ -22,6 +30,9 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin var valueTableDictionary = valueTable.ToDictionary(); builder.AddNamedValueTable(match.Groups[1].Value, valueTableDictionary, valueTable); } + else + m_observer.ValueTableDefinitionSyntaxError(); + return true; } } diff --git a/DbcParserLib/Parsers/ValueTableLineParser.cs b/DbcParserLib/Parsers/ValueTableLineParser.cs index 106f71b..7771a4d 100644 --- a/DbcParserLib/Parsers/ValueTableLineParser.cs +++ b/DbcParserLib/Parsers/ValueTableLineParser.cs @@ -1,5 +1,6 @@ using System; using System.Text.RegularExpressions; +using DbcParserLib.Observers; namespace DbcParserLib.Parsers { @@ -9,6 +10,13 @@ internal class ValueTableLineParser : ILineParser private const string ValueTableLinkParsingRegex = @"VAL_\s+(\d+)\s+([a-zA-Z_][\w]*)\s+([a-zA-Z_][\w]*)\s*;"; private const string ValueTableParsingRegex = @"VAL_\s+(?:(?:(\d+)\s+([a-zA-Z_][\w]*))|([a-zA-Z_][\w]*))\s+((?:\d+\s+(?:""[^""]*"")\s+)*)\s*;"; + private readonly IParseFailureObserver m_observer; + + public ValueTableLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { var cleanLine = line.Trim(' '); @@ -20,6 +28,7 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (match.Success) { builder.LinkNamedTableToSignal(uint.Parse(match.Groups[1].Value), match.Groups[2].Value, match.Groups[3].Value); + return true; } match = Regex.Match(cleanLine, ValueTableParsingRegex); @@ -31,8 +40,10 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin builder.LinkTableValuesToEnvironmentVariable(match.Groups[3].Value, valueTableDictionary); else builder.LinkTableValuesToSignal(uint.Parse(match.Groups[1].Value), match.Groups[2].Value, valueTableDictionary, valueTable); + return true; } + m_observer.ValueTableSyntaxError(); return true; } } diff --git a/Demo/Form1.cs b/Demo/Form1.cs index 9c6e1a9..a7540a7 100644 --- a/Demo/Form1.cs +++ b/Demo/Form1.cs @@ -1,16 +1,11 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; -using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using DbcParserLib; -using DbcParserLib.Model; +using DbcParserLib.Observers; /* * ------------------------------------ @@ -25,8 +20,9 @@ namespace Demo { public partial class Form1 : Form { - public DataTable dtMessages = new DataTable(); - public DataTable dtSignals = new DataTable(); + public DataTable dtMessages = new(); + public DataTable dtSignals = new(); + private readonly SimpleFailureObserver m_failureObserver = new(); public Form1() { @@ -58,7 +54,7 @@ private void Form1_Load(object sender, EventArgs e) private void buttonLoadDbc_Click(object sender, EventArgs e) { - OpenFileDialog openFileDialog = new System.Windows.Forms.OpenFileDialog(); + OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Title = "Open dbc file"; openFileDialog.FileName = ""; openFileDialog.Filter = "DBC File|*.dbc"; @@ -74,7 +70,13 @@ public void LoadDbc(string filePath) { try { + // Comment this line to remove parsing failure management (errors will be silent) + // You can provide your own IParseObserver implementation to customize parsing failure management + Parser.SetParsingFailuresObserver(m_failureObserver); + var dbc = Parser.ParseFromPath(filePath); + ShowErrors(); + textBoxPath.Text = filePath; PopulateView(dbc); } @@ -85,6 +87,16 @@ public void LoadDbc(string filePath) } } + private void ShowErrors() + { + var errors = m_failureObserver.GetErrorList(); + if (errors.Count > 0) + { + MessageBox.Show(string.Join(Environment.NewLine, errors), "Parsing failures!", MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + public void PopulateView(Dbc dbc) { // Clear controls diff --git a/Demo/Program.cs b/Demo/Program.cs index 1d3784d..a169724 100644 --- a/Demo/Program.cs +++ b/Demo/Program.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using System.Windows.Forms; namespace Demo