using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.TwinCAT; namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests; [Trait("Category", "Unit")] public sealed class TwinCATAmsAddressTests { /// Verifies that TryParse accepts valid AMS addresses in various formats. /// The raw AMS address string to parse. /// The expected AMS Net ID after parsing. /// The expected AMS port after parsing. [Theory] [InlineData("ads://5.23.91.23.1.1:851", "5.23.91.23.1.1", 851)] [InlineData("ads://5.23.91.23.1.1:852", "5.23.91.23.1.1", 852)] [InlineData("ads://5.23.91.23.1.1", "5.23.91.23.1.1", 851)] // default port [InlineData("ads://127.0.0.1.1.1:851", "127.0.0.1.1.1", 851)] [InlineData("ADS://5.23.91.23.1.1:851", "5.23.91.23.1.1", 851)] // case-insensitive scheme [InlineData("ads://10.0.0.1.1.1:10000", "10.0.0.1.1.1", 10000)] // system service port public void TryParse_accepts_valid_ams_addresses(string input, string netId, int port) { var parsed = TwinCATAmsAddress.TryParse(input); parsed.ShouldNotBeNull(); parsed.NetId.ShouldBe(netId); parsed.Port.ShouldBe(port); } /// Verifies that TryParse rejects invalid AMS address forms. /// The invalid AMS address string that should be rejected. [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] [InlineData("tcp://5.23.91.23.1.1:851")] // wrong scheme [InlineData("ads:5.23.91.23.1.1:851")] // missing // [InlineData("ads://")] // empty body [InlineData("ads://5.23.91.23.1:851")] // only 5 octets [InlineData("ads://5.23.91.23.1.1.1:851")] // 7 octets [InlineData("ads://5.23.91.256.1.1:851")] // octet > 255 [InlineData("ads://5.23.91.23.1.1:0")] // port 0 [InlineData("ads://5.23.91.23.1.1:65536")] // port out of range [InlineData("ads://5.23.91.23.1.1:abc")] // non-numeric port [InlineData("ads://a.b.c.d.e.f:851")] // non-numeric octets public void TryParse_rejects_invalid_forms(string? input) { TwinCATAmsAddress.TryParse(input).ShouldBeNull(); } /// Verifies that ToString produces canonical AMS address strings. /// The AMS Net ID to use. /// The AMS port to use. /// The expected canonical string representation. [Theory] [InlineData("5.23.91.23.1.1", 851, "ads://5.23.91.23.1.1")] // default port stripped [InlineData("5.23.91.23.1.1", 852, "ads://5.23.91.23.1.1:852")] public void ToString_canonicalises(string netId, int port, string expected) { new TwinCATAmsAddress(netId, port).ToString().ShouldBe(expected); } /// Verifies that parsing and stringifying an AMS address is stable. [Fact] public void RoundTrip_is_stable() { const string input = "ads://5.23.91.23.1.1:852"; var parsed = TwinCATAmsAddress.TryParse(input)!; TwinCATAmsAddress.TryParse(parsed.ToString()).ShouldBe(parsed); } }