Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/L5Sharp.Core/Common/Instruction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1801,7 +1801,7 @@ private Argument[] ParseArguments()

var signature = _text.Substring(start, length);

return Regex.Split(signature, ArgumentSplitPattern).Select(a => new Argument(a)).ToArray();
return Regex.Split(signature, ArgumentSplitPattern).Select(a => new Argument(a.Trim())).ToArray();
}

/// <summary>
Expand Down
11 changes: 7 additions & 4 deletions src/L5Sharp.Core/Enums/ArgumentType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@ private ArgumentType(string name, string value) : base(name, value)
public static ArgumentType Of(string value)
{
if (string.IsNullOrEmpty(value)) return Empty;
if (value.StartsWith('\'') && value.EndsWith('\'')) return String;
if (Radix.TryInfer(value, out _)) return Atomic;

var trimmed = value.Trim();

if (trimmed.StartsWith('\'') && trimmed.EndsWith('\'')) return String;
if (Radix.TryInfer(trimmed, out _)) return Atomic;
// We can use the tag name patter match because system components should pass this as well
if (TagName.IsTag(value)) return Reference;
if (TagName.IsTag(trimmed)) return Reference;
// todo I think we need to include bitwise operators (AND, OR, XOR, etc.)
if (value.IndexOfAny(['=', '>', '<', '+', '-', '*', '/', '(', ')']) >= 0) return Expression;
if (trimmed.IndexOfAny(['=', '>', '<', '+', '-', '*', '/', '(', ')']) >= 0) return Expression;
return Unknown;
}

Expand Down
50 changes: 50 additions & 0 deletions tests/L5Sharp.Tests.Core/Code/RungTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,54 @@ public Task SetTextToNullThenCommentThenTextAgainShouldBeValid()

return VerifyXml(xml);
}

[TestCase("MOV(Flow_Rate, Flow_Rate_Scaled);", new[] { "Flow_Rate", "Flow_Rate_Scaled" })]
[TestCase("ADD(Tank_Level.PV, Tank_Level.Offset, Tank_Level.Corrected);", new[] { "Tank_Level.PV", "Tank_Level.Offset", "Tank_Level.Corrected" })]
[TestCase("MOV(Motor1.Status, PanelLights.Green);", new[] { "Motor1.Status", "PanelLights.Green" })]
[TestCase("TON(Motor1_Timer, Timer_Preset, Timer_Accum);", new[] { "Motor1_Timer", "Timer_Preset", "Timer_Accum" })]
[TestCase("MOV(5000, Motor1_Timer.PRE);", new[] { "Motor1_Timer.PRE" })]
public void Tags_RungWithMultipleArgs_ShouldCountAllTagReferences(string text, string[] expectedTags)
{
var rung = new Rung(text);

var tags = rung.Tags().ToList();

tags.Should().HaveCount(expectedTags.Length);
foreach (var expected in expectedTags)
{
tags.Should().Contain(t => (string)t == expected);
}
}

[TestCase("XIC(Motor1_Start)OTE(Motor1_Start);", new[] { "Motor1_Start" }, new[] { 2 })]
[TestCase("XIC(Motor1_Start)XIO(Motor1_Stop)OTE(Motor1_Start);", new[] { "Motor1_Start", "Motor1_Stop" }, new[] { 2, 1 })]
[TestCase("XIC(Motor1_Status.Running)OTE(Motor1_Status.Running);", new[] { "Motor1_Status.Running" }, new[] { 2 })]
public void Tags_RungWithDuplicateTagInMultipleInstructions_ShouldCountEachOccurrence(
string text, string[] tagNames, int[] expectedCounts)
{
var rung = new Rung(text);

var tags = rung.Tags().ToList();

tags.Should().HaveCount(expectedCounts.Sum());
for (var i = 0; i < tagNames.Length; i++)
{
tags.Count(t => (string)t == tagNames[i]).Should().Be(expectedCounts[i]);
}
}

[Test]
public void Tags_RungWithBranchAndNestedInstructions_ShouldCountAllReferences()
{
var rung = new Rung("[XIC(Start),XIO(Stop)]OTE(Motor);MOV(Motor_Status, Log);");

var tags = rung.Tags().ToList();

tags.Should().HaveCount(5);
tags.Count(t => (string)t == "Start").Should().Be(1);
tags.Count(t => (string)t == "Stop").Should().Be(1);
tags.Count(t => (string)t == "Motor").Should().Be(1);
tags.Count(t => (string)t == "Motor_Status").Should().Be(1);
tags.Count(t => (string)t == "Log").Should().Be(1);
}
}
10 changes: 10 additions & 0 deletions tests/L5Sharp.Tests.Core/Common/ArgumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,14 @@ public void ToNeutralText_WhenCalled_ShouldBeExpected()
text.Should().NotBeNull();
text.ToString().Should().Be("SomeTag > 100");
}

[TestCase(" Motor1.Status")]
[TestCase(" MyTag")]
public void New_TagWithLeadingWhitespace_ShouldBeReference(string value)
{
Argument argument = value;

argument.Type.Should().Be(ArgumentType.Reference);
argument.IsReference.Should().BeTrue();
}
}
12 changes: 12 additions & 0 deletions tests/L5Sharp.Tests.Core/Common/InstructionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -356,5 +356,17 @@ public void ToString_WhenCalled_ShouldBeText()

text.Should().Be("OTE(MyTag)");
}

[TestCase("MOV(Motor1.Status, PanelLights.Green)", 2)]
[TestCase("ADD(Tank_Level.PV, Tank_Level.Offset, Tank_Level.Corrected)", 3)]
public void Parse_CommaSeparatedArgsWithWhitespace_ShouldParseAllAsReferences(string text, int expectedCount)
{
var instructions = Instruction.Parse(text).ToList();

var arguments = instructions[0].Arguments.ToList();

arguments.Should().HaveCount(expectedCount);
arguments.Should().AllSatisfy(a => a.IsReference.Should().BeTrue());
}
}
}
14 changes: 14 additions & 0 deletions tests/L5Sharp.Tests.Core/Common/TagNameTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -688,5 +688,19 @@ public void CompareTo_Null_ShouldBeOne()

result.Should().Be(1);
}

[TestCase("MyTag")]
[TestCase("Motor1.Status")]
public void IsTag_ValidTagName_ShouldReturnTrue(string value)
{
TagName.IsTag(value).Should().BeTrue();
}

[TestCase(" MyTag")]
[TestCase(" Motor1.Status")]
public void IsTag_TagWithLeadingSpace_ShouldReturnFalse(string value)
{
TagName.IsTag(value).Should().BeFalse();
}
}
}
9 changes: 9 additions & 0 deletions tests/L5Sharp.Tests.Core/Enums/ArgumentTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,13 @@ public void Of_ValidTagName_ShouldBeTag()

type.Should().Be(ArgumentType.Reference);
}

[TestCase(" MyTag")]
[TestCase(" Motor1.Status")]
public void Of_TagWithLeadingSpace_ShouldBeReference(string value)
{
var type = ArgumentType.Of(value);

type.Should().Be(ArgumentType.Reference);
}
}
46 changes: 46 additions & 0 deletions tests/L5Sharp.Tests.Core/L5XReferencesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,52 @@ public void TagReferences_ProjectWithSimpleRungReferences_ShouldBeExpectedCount(
references.Should().HaveCount(3);
}

[Test]
public void TagReferences_RungWithCommaSeparatedArgs_ShouldCountAllOccurrences()
{
var project = L5X.New("MyProject", "1756-L84E", "34.1")
.Add(Tag.Named("Source").WithValue(100).Build())
.Add(Tag.Named("Source.Member").WithValue(200).Build())
.Add(Routine.Rll("MyRoutine").InProgram("MyProgram")
.WithRung("MOV(Source, Source.Member);")
.Build());

var sourceRefs = project.Tags.Get("Source").References().ToList();
var memberRefs = project.Tags.Get("Source.Member").References().ToList();

sourceRefs.Should().HaveCount(1);
memberRefs.Should().HaveCount(1);
}

[Test]
public void TagReferences_SameTagUsedTwiceInDifferentInstructions_ShouldCountBoth()
{
var project = L5X.New("MyProject", "1756-L84E", "34.1")
.Add(Tag.Named("MyTag").WithValue(123).Build())
.Add(Routine.Rll("MyRoutine").InProgram("MyProgram")
.WithRung("XIC(MyTag)OTE(MyTag);")
.Build());

var references = project.Tags.Get("MyTag").References().ToList();

references.Should().HaveCount(2);
}

[Test]
public void TagReferences_SameTagUsedTwiceInSameInstruction_ShouldCountBoth()
{
var project = L5X.New("MyProject", "1756-L84E", "34.1")
.Add(Tag.Named("MyTag").WithValue(100).Build())
.Add(Tag.Named("Dest").WithValue(0).Build())
.Add(Routine.Rll("MyRoutine").InProgram("MyProgram")
.WithRung("ADD(MyTag, MyTag, Dest);")
.Build());

var references = project.Tags.Get("MyTag").References().ToList();

references.Should().HaveCount(2);
}

#region TestFile

[Test]
Expand Down
Loading