120 lines
4.4 KiB
C#
120 lines
4.4 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Tests;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public sealed class S7AddressParserTests
|
|
{
|
|
// --- Data blocks ---
|
|
|
|
[Theory]
|
|
[InlineData("DB1.DBX0.0", 1, S7Size.Bit, 0, 0)]
|
|
[InlineData("DB1.DBX0.7", 1, S7Size.Bit, 0, 7)]
|
|
[InlineData("DB1.DBB0", 1, S7Size.Byte, 0, 0)]
|
|
[InlineData("DB1.DBW0", 1, S7Size.Word, 0, 0)]
|
|
[InlineData("DB1.DBD4", 1, S7Size.DWord, 4, 0)]
|
|
[InlineData("DB10.DBW100", 10, S7Size.Word, 100, 0)]
|
|
[InlineData("DB1.DBX15.3", 1, S7Size.Bit, 15, 3)]
|
|
public void Parse_data_block_addresses(string input, int db, S7Size size, int byteOff, int bitOff)
|
|
{
|
|
var r = S7AddressParser.Parse(input);
|
|
r.Area.ShouldBe(S7Area.DataBlock);
|
|
r.DbNumber.ShouldBe(db);
|
|
r.Size.ShouldBe(size);
|
|
r.ByteOffset.ShouldBe(byteOff);
|
|
r.BitOffset.ShouldBe(bitOff);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("db1.dbw0", 1, S7Size.Word, 0)]
|
|
[InlineData(" DB1.DBW0 ", 1, S7Size.Word, 0)] // trim whitespace
|
|
public void Parse_is_case_insensitive_and_trims(string input, int db, S7Size size, int off)
|
|
{
|
|
var r = S7AddressParser.Parse(input);
|
|
r.Area.ShouldBe(S7Area.DataBlock);
|
|
r.DbNumber.ShouldBe(db);
|
|
r.Size.ShouldBe(size);
|
|
r.ByteOffset.ShouldBe(off);
|
|
}
|
|
|
|
// --- M / I / Q ---
|
|
|
|
[Theory]
|
|
[InlineData("MB0", S7Area.Memory, S7Size.Byte, 0, 0)]
|
|
[InlineData("MW10", S7Area.Memory, S7Size.Word, 10, 0)]
|
|
[InlineData("MD4", S7Area.Memory, S7Size.DWord, 4, 0)]
|
|
[InlineData("M0.0", S7Area.Memory, S7Size.Bit, 0, 0)]
|
|
[InlineData("M255.7", S7Area.Memory, S7Size.Bit, 255, 7)]
|
|
[InlineData("IB0", S7Area.Input, S7Size.Byte, 0, 0)]
|
|
[InlineData("IW0", S7Area.Input, S7Size.Word, 0, 0)]
|
|
[InlineData("I0.0", S7Area.Input, S7Size.Bit, 0, 0)]
|
|
[InlineData("QB0", S7Area.Output, S7Size.Byte, 0, 0)]
|
|
[InlineData("QW0", S7Area.Output, S7Size.Word, 0, 0)]
|
|
[InlineData("Q0.0", S7Area.Output, S7Size.Bit, 0, 0)]
|
|
[InlineData("QD4", S7Area.Output, S7Size.DWord, 4, 0)]
|
|
public void Parse_MIQ_addresses(string input, S7Area area, S7Size size, int byteOff, int bitOff)
|
|
{
|
|
var r = S7AddressParser.Parse(input);
|
|
r.Area.ShouldBe(area);
|
|
r.DbNumber.ShouldBe(0);
|
|
r.Size.ShouldBe(size);
|
|
r.ByteOffset.ShouldBe(byteOff);
|
|
r.BitOffset.ShouldBe(bitOff);
|
|
}
|
|
|
|
// --- Timers / counters ---
|
|
|
|
[Theory]
|
|
[InlineData("T0", S7Area.Timer, 0)]
|
|
[InlineData("T15", S7Area.Timer, 15)]
|
|
[InlineData("C0", S7Area.Counter, 0)]
|
|
[InlineData("C10", S7Area.Counter, 10)]
|
|
public void Parse_timer_and_counter(string input, S7Area area, int number)
|
|
{
|
|
var r = S7AddressParser.Parse(input);
|
|
r.Area.ShouldBe(area);
|
|
r.ByteOffset.ShouldBe(number);
|
|
r.Size.ShouldBe(S7Size.Word, "timers + counters are 16-bit opaque");
|
|
}
|
|
|
|
// --- Reject garbage ---
|
|
|
|
[Theory]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
[InlineData("Z0")] // unknown area
|
|
[InlineData("DB")] // no number or tail
|
|
[InlineData("DB1")] // no tail
|
|
[InlineData("DB1.")] // empty tail
|
|
[InlineData("DB1.DBX0")] // bit size without .bit
|
|
[InlineData("DB1.DBX0.8")] // bit 8 out of range
|
|
[InlineData("DB1.DBW0.0")] // word with bit suffix
|
|
[InlineData("DB0.DBW0")] // db 0 invalid
|
|
[InlineData("DBA.DBW0")] // non-numeric db
|
|
[InlineData("DB1.DBQ0")] // invalid size letter
|
|
[InlineData("M")] // no offset
|
|
[InlineData("M0")] // bit access needs .bit
|
|
[InlineData("M0.8")] // bit 8
|
|
[InlineData("MB-1")] // negative offset
|
|
[InlineData("MW")] // no offset digits
|
|
[InlineData("TA")] // non-numeric timer
|
|
public void Parse_rejects_invalid(string bad)
|
|
=> Should.Throw<FormatException>(() => S7AddressParser.Parse(bad));
|
|
|
|
[Fact]
|
|
public void TryParse_returns_false_for_garbage_without_throwing()
|
|
{
|
|
S7AddressParser.TryParse("not-an-address", out var r).ShouldBeFalse();
|
|
r.ShouldBe(default);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryParse_returns_true_for_valid_address()
|
|
{
|
|
S7AddressParser.TryParse("DB1.DBW0", out var r).ShouldBeTrue();
|
|
r.DbNumber.ShouldBe(1);
|
|
r.Size.ShouldBe(S7Size.Word);
|
|
}
|
|
}
|