3c908f1df0
Review at HEAD 7286d320. AdminUI-002: IsValidJson null/blank -> friendly error (was
ArgumentNullException). AdminUI-003: DriverStatusPanel Reconnect/Restart dispose CTS (build-
verified, live /run deferred). AdminUI-005: HistorianWonderware picker URL-encodes tag name.
AdminUI-008: Format round-trip test. 001 (script-page authz) + 004 (hub [Authorize]) left
Open as cross-cutting w/ Host/Security.
30 lines
1.4 KiB
C#
30 lines
1.4 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
|
|
|
|
public sealed class HistorianWonderwareAddressBuilderTests
|
|
{
|
|
[Theory]
|
|
[InlineData("SysTimeHour", "Cyclic", 60, "SysTimeHour?mode=Cyclic&interval=60")]
|
|
[InlineData("ReactorTemp", "Last", 1, "ReactorTemp?mode=Last&interval=1")]
|
|
[InlineData("FlowRate", "Delta", 30, "FlowRate?mode=Delta&interval=30")]
|
|
public void Build_Canonical(string tag, string mode, int interval, string expected)
|
|
=> HistorianWonderwareAddressBuilder.Build(tag, mode, interval).ShouldBe(expected);
|
|
|
|
/// <summary>A tag name carrying query-reserved characters is percent-encoded so the produced
|
|
/// address stays a well-formed query string (AdminUI-005). With "A&B?C" the '&' and '?'
|
|
/// must not be read as a query separator / start, so they are escaped.</summary>
|
|
[Fact]
|
|
public void Build_escapes_reserved_characters_in_tag_name()
|
|
{
|
|
var result = HistorianWonderwareAddressBuilder.Build("A&B?C", "Cyclic", 60);
|
|
|
|
// The only literal '?' is the query separator the builder inserts; the only literal '&'
|
|
// is the one between mode and interval. The reserved characters in the name are escaped.
|
|
result.ShouldBe("A%26B%3FC?mode=Cyclic&interval=60");
|
|
result.IndexOf('?').ShouldBe(result.IndexOf("?mode=", System.StringComparison.Ordinal));
|
|
}
|
|
}
|