using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Runtime;
namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Tests.Runtime;
///
/// Gitea #610 — pins 's Galaxy row against the REAL write encoder
/// (). The driver receives the CLR array type of the node's DataType and no
/// other: NOT because the SDK checks it (it skips its own type check on a node with an OnWriteValue
/// handler, which every writable equipment node has) but because OtOpcUaNodeManager.EvaluateEquipmentWriteStructure
/// refuses an array whose element type does not match the node's DataType exactly (#610 review MAJOR-1). So
/// for every Tag.DataType the server can materialise, the node is advertised writable exactly when the
/// encoder accepts that array type.
///
[Trait("Category", "Unit")]
public sealed class GalaxyArrayWriteSupportParityTests
{
// Tag.DataType name → the CLR array the OPC UA stack delivers for a 1-D write of that type.
private static readonly Dictionary ClrArrays = new()
{
["Boolean"] = new[] { true, false },
["SByte"] = new sbyte[] { 1, 2 },
["Byte"] = new byte[] { 1, 2 },
["Int16"] = new short[] { 1, 2 },
["UInt16"] = new ushort[] { 1, 2 },
["Int32"] = new[] { 1, 2 },
["UInt32"] = new uint[] { 1, 2 },
["Int64"] = new long[] { 1, 2 },
["UInt64"] = new ulong[] { 1, 2 },
["Float"] = new[] { 1f, 2f },
["Double"] = new[] { 1d, 2d },
["String"] = new[] { "a", "b" },
["DateTime"] = new[] { DateTime.UtcNow, DateTime.UtcNow },
};
public static TheoryData DataTypes() => new(ClrArrays.Keys);
[Theory]
[MemberData(nameof(DataTypes))]
public void Table_agrees_with_MxValueEncoder(string dataType)
{
bool encoderAccepts;
try
{
MxValueEncoder.Encode(ClrArrays[dataType]);
encoderAccepts = true;
}
catch (ArgumentException)
{
encoderAccepts = false;
}
// UInt32 / UInt64 used to be a hand-written exclusion here, because CLR array covariance let uint[] /
// ulong[] match the encoder's int[] / long[] arms and be encoded by reinterpreting their bits. The encoder
// now refuses them itself, so the table and the encoder agree with no special case.
DriverArrayWriteSupport.Supports(DriverTypeNames.Galaxy, dataType, "{\"FullName\":\"Obj.Attr\",\"isArray\":true,\"arrayLength\":2}")
.ShouldBe(encoderAccepts, dataType);
}
/// Positive control: the theory above sees both answers, so it is not vacuously all-refused.
[Fact]
public void The_matrix_contains_both_answers() =>
ClrArrays.Keys
.Select(dt => DriverArrayWriteSupport.Supports(DriverTypeNames.Galaxy, dt, "{\"isArray\":true,\"arrayLength\":2}"))
.ToHashSet()
.ShouldBe(new[] { true, false }, ignoreOrder: true);
}