test(runtime): cover disabled-array + zero-length in artifact parity round-trip (review)
This commit is contained in:
+51
-2
@@ -102,6 +102,9 @@ public sealed class DeploymentArtifactArrayParityTests
|
||||
// round-trip (it can't be unit-tested directly because it's private). A truly malformed TagConfig
|
||||
// string would cause ExtractTagFullName to return "" and break the SequenceEqual on other fields,
|
||||
// so the throws/malformed path is covered by the composer unit test, not here.
|
||||
// NOTE (review M-1): only the string-type bad-length case is round-tripped here. The
|
||||
// negative/float/overflow arrayLength reject paths are covered on the composer side
|
||||
// (ExtractTagArrayTests) and do not need duplication in this artifact parity test.
|
||||
var arrayBadLengthTag = new Tag
|
||||
{
|
||||
TagId = "tag-array-badlen",
|
||||
@@ -113,12 +116,40 @@ public sealed class DeploymentArtifactArrayParityTests
|
||||
AccessLevel = TagAccessLevel.Read,
|
||||
TagConfig = "{\"FullName\":\"40004\",\"isArray\":true,\"arrayLength\":\"sixteen\"}",
|
||||
};
|
||||
// I-1: isArray:false with a non-zero arrayLength — the artifact-side guard must gate arrayLength
|
||||
// under isArray, so the length is discarded and IsArray==false, ArrayLength==null on both sides.
|
||||
// Pins that a future removal of the isArray gate would be caught here.
|
||||
var arrayDisabledTag = new Tag
|
||||
{
|
||||
TagId = "tag-array-disabled",
|
||||
DriverInstanceId = "drv-modbus",
|
||||
EquipmentId = "eq-1",
|
||||
FolderPath = null,
|
||||
Name = "Setpoint",
|
||||
DataType = "Float",
|
||||
AccessLevel = TagAccessLevel.ReadWrite,
|
||||
TagConfig = "{\"FullName\":\"40005\",\"isArray\":false,\"arrayLength\":8}",
|
||||
};
|
||||
// I-2: isArray:true with arrayLength:0 — zero is a legal explicit dimension bound (e.g. dynamic
|
||||
// array with declared-but-unset size). Must decode to IsArray==true, ArrayLength==0u on both sides.
|
||||
// Pins that a future change treating 0 as absent would be caught here.
|
||||
var arrayZeroLengthTag = new Tag
|
||||
{
|
||||
TagId = "tag-array-zerolen",
|
||||
DriverInstanceId = "drv-modbus",
|
||||
EquipmentId = "eq-1",
|
||||
FolderPath = null,
|
||||
Name = "Empty",
|
||||
DataType = "Int32",
|
||||
AccessLevel = TagAccessLevel.Read,
|
||||
TagConfig = "{\"FullName\":\"40006\",\"isArray\":true,\"arrayLength\":0}",
|
||||
};
|
||||
|
||||
var areas = new[] { area };
|
||||
var lines = new[] { line };
|
||||
var equipment = new[] { equip };
|
||||
var drivers = new[] { driver };
|
||||
var tags = new[] { arrayBoundedTag, scalarTag, arrayUnboundedTag, arrayBadLengthTag };
|
||||
var tags = new[] { arrayBoundedTag, scalarTag, arrayUnboundedTag, arrayBadLengthTag, arrayDisabledTag, arrayZeroLengthTag };
|
||||
var namespaces = new[] { ns };
|
||||
|
||||
// ---- Side 1: the live-edit composer ----
|
||||
@@ -142,13 +173,15 @@ public sealed class DeploymentArtifactArrayParityTests
|
||||
ToSnapshot(scalarTag),
|
||||
ToSnapshot(arrayUnboundedTag),
|
||||
ToSnapshot(arrayBadLengthTag),
|
||||
ToSnapshot(arrayDisabledTag),
|
||||
ToSnapshot(arrayZeroLengthTag),
|
||||
},
|
||||
});
|
||||
|
||||
var decoded = DeploymentArtifact.ParseComposition(blob);
|
||||
|
||||
// ---- Full byte-parity: every field, same order (positional-record value equality) ----
|
||||
decoded.EquipmentTags.Count.ShouldBe(4);
|
||||
decoded.EquipmentTags.Count.ShouldBe(6);
|
||||
decoded.EquipmentTags.SequenceEqual(composed.EquipmentTags).ShouldBeTrue();
|
||||
|
||||
// Spell out the array fields per-tag so a divergence names the offending tag.
|
||||
@@ -177,6 +210,22 @@ public sealed class DeploymentArtifactArrayParityTests
|
||||
arrayBadLength.ArrayLength.ShouldBeNull();
|
||||
composed.EquipmentTags.Single(t => t.TagId == "tag-array-badlen").IsArray.ShouldBeTrue();
|
||||
composed.EquipmentTags.Single(t => t.TagId == "tag-array-badlen").ArrayLength.ShouldBeNull();
|
||||
|
||||
// I-1: isArray:false with a non-zero arrayLength ⇒ (false, null) on both sides.
|
||||
// The artifact-side isArray gate must suppress arrayLength even when it is present in the blob.
|
||||
var arrayDisabled = decoded.EquipmentTags.Single(t => t.TagId == "tag-array-disabled");
|
||||
arrayDisabled.IsArray.ShouldBeFalse();
|
||||
arrayDisabled.ArrayLength.ShouldBeNull();
|
||||
composed.EquipmentTags.Single(t => t.TagId == "tag-array-disabled").IsArray.ShouldBeFalse();
|
||||
composed.EquipmentTags.Single(t => t.TagId == "tag-array-disabled").ArrayLength.ShouldBeNull();
|
||||
|
||||
// I-2: isArray:true with arrayLength:0 ⇒ (true, 0u) on both sides.
|
||||
// Zero is a legal explicit dimension bound; it must not be treated as absent.
|
||||
var arrayZeroLength = decoded.EquipmentTags.Single(t => t.TagId == "tag-array-zerolen");
|
||||
arrayZeroLength.IsArray.ShouldBeTrue();
|
||||
arrayZeroLength.ArrayLength.ShouldBe(0u);
|
||||
composed.EquipmentTags.Single(t => t.TagId == "tag-array-zerolen").IsArray.ShouldBeTrue();
|
||||
composed.EquipmentTags.Single(t => t.TagId == "tag-array-zerolen").ArrayLength.ShouldBe(0u);
|
||||
}
|
||||
|
||||
/// <summary>The Pascal-case snapshot a <see cref="Tag"/> EF entity serialises to in the artifact
|
||||
|
||||
Reference in New Issue
Block a user