docs: complete XML doc comments via fixdocs (2757 to 131 findings)

Add missing <returns>/<param>/<summary>/<typeparam> tags and clean up
misused inheritdoc across 481 files so the documented API surface is
complete. Documentation-only (zero code lines changed). The 131 remaining
findings are inheritdoc-style warnings deliberately left to preserve
hand-written implementation rationale (plan-decision notes, race-condition
explanations).
This commit is contained in:
Joseph Doherty
2026-06-03 12:34:34 -04:00
parent c6d9b20d9f
commit bd6c0b4d3d
481 changed files with 2550 additions and 1668 deletions
@@ -21,6 +21,7 @@ public sealed class AbCipDriverPageFormSerializationTests
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
};
/// <summary>Verifies that serializing and deserializing an <see cref="AbCipDriverOptions"/> round-trip preserves all known fields.</summary>
[Fact]
public void RoundTrip_PreservesKnownFields()
{
@@ -71,6 +72,7 @@ public sealed class AbCipDriverPageFormSerializationTests
back.Tags[0].DataType.ShouldBe(AbCipDataType.Real);
}
/// <summary>Verifies that deserializing JSON with unknown fields drops them without error.</summary>
[Fact]
public void Deserialize_DropsUnknownFields()
{
@@ -86,6 +88,7 @@ public sealed class AbCipDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(10);
}
/// <summary>Verifies that a device row round-trips correctly through its definition.</summary>
[Fact]
public void DeviceRow_round_trips_through_definition()
{
@@ -101,6 +104,7 @@ public sealed class AbCipDriverPageFormSerializationTests
back.DeviceName.ShouldBe("PLC-A");
}
/// <summary>Verifies that editing one field of a device row preserves all other fields.</summary>
[Fact]
public void DeviceRow_preserves_unedited_fields()
{
@@ -116,6 +120,7 @@ public sealed class AbCipDriverPageFormSerializationTests
back.ConnectionSize.ShouldBe(4002);
}
/// <summary>Verifies that a tag row round-trips correctly through its definition.</summary>
[Fact]
public void TagRow_round_trips_through_definition()
{
@@ -134,6 +139,7 @@ public sealed class AbCipDriverPageFormSerializationTests
back.Writable.ShouldBeTrue();
}
/// <summary>Verifies that editing one field of a tag row preserves all other fields.</summary>
[Fact]
public void TagRow_preserves_unedited_fields()
{
@@ -154,6 +160,7 @@ public sealed class AbCipDriverPageFormSerializationTests
back.Members[0].Name.ShouldBe("Sub");
}
/// <summary>Verifies that device row validation rejects a duplicate host address.</summary>
[Fact]
public void ValidateDeviceRow_rejects_duplicate_host()
{
@@ -162,6 +169,7 @@ public sealed class AbCipDriverPageFormSerializationTests
.ShouldNotBeNull();
}
/// <summary>Verifies that tag row validation rejects a duplicate tag name.</summary>
[Fact]
public void ValidateTagRow_rejects_duplicate_name()
{
@@ -170,6 +178,7 @@ public sealed class AbCipDriverPageFormSerializationTests
.ShouldNotBeNull();
}
/// <summary>Verifies that device and tag lists survive a full options serialize/deserialize round-trip.</summary>
[Fact]
public void Device_and_tag_lists_survive_options_serialize_round_trip()
{
@@ -22,6 +22,7 @@ public sealed class AbLegacyDriverPageFormSerializationTests
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
};
/// <summary>Verifies that round-trip serialization preserves all known fields.</summary>
[Fact]
public void RoundTrip_PreservesKnownFields()
{
@@ -71,6 +72,7 @@ public sealed class AbLegacyDriverPageFormSerializationTests
back.Tags[1].DataType.ShouldBe(AbLegacyDataType.Bit);
}
/// <summary>Verifies that deserialization silently drops unknown fields.</summary>
[Fact]
public void Deserialize_DropsUnknownFields()
{
@@ -86,6 +88,7 @@ public sealed class AbLegacyDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(10);
}
/// <summary>Verifies that a device row round-trips through its definition.</summary>
[Fact]
public void DeviceRow_round_trips_through_definition()
{
@@ -101,6 +104,7 @@ public sealed class AbLegacyDriverPageFormSerializationTests
back.DeviceName.ShouldBe("PLC-A");
}
/// <summary>Verifies that a device row preserves unedited fields when converting back to definition.</summary>
[Fact]
public void DeviceRow_preserves_unedited_fields()
{
@@ -114,6 +118,7 @@ public sealed class AbLegacyDriverPageFormSerializationTests
back.DeviceName.ShouldBe("PLC-A");
}
/// <summary>Verifies that a tag row round-trips through its definition.</summary>
[Fact]
public void TagRow_round_trips_through_definition()
{
@@ -132,6 +137,7 @@ public sealed class AbLegacyDriverPageFormSerializationTests
back.Writable.ShouldBeTrue();
}
/// <summary>Verifies that a tag row preserves unedited fields when converting back to definition.</summary>
[Fact]
public void TagRow_preserves_unedited_fields()
{
@@ -146,6 +152,7 @@ public sealed class AbLegacyDriverPageFormSerializationTests
back.WriteIdempotent.ShouldBeTrue();
}
/// <summary>Verifies that device row validation rejects a duplicate host address.</summary>
[Fact]
public void ValidateDeviceRow_rejects_duplicate_host()
{
@@ -154,6 +161,7 @@ public sealed class AbLegacyDriverPageFormSerializationTests
.ShouldNotBeNull();
}
/// <summary>Verifies that tag row validation rejects a duplicate tag name.</summary>
[Fact]
public void ValidateTagRow_rejects_duplicate_name()
{
@@ -162,6 +170,7 @@ public sealed class AbLegacyDriverPageFormSerializationTests
.ShouldNotBeNull();
}
/// <summary>Verifies that device and tag lists survive a full options serialization round-trip.</summary>
[Fact]
public void Device_and_tag_lists_survive_options_serialize_round_trip()
{
@@ -14,6 +14,8 @@ public sealed class BrowseSessionReaperTests
private static BrowseSessionReaper NewReaper(BrowseSessionRegistry registry) =>
new(registry, NullLogger<BrowseSessionReaper>.Instance);
/// <summary>Verifies that ReapOnceAsync evicts a session that has been idle beyond the timeout.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReapOnceAsync_evicts_idle_session()
{
@@ -31,6 +33,8 @@ public sealed class BrowseSessionReaperTests
session.Disposed.ShouldBeTrue();
}
/// <summary>Verifies that ReapOnceAsync preserves a recently used session.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReapOnceAsync_preserves_recent_session()
{
@@ -45,6 +49,8 @@ public sealed class BrowseSessionReaperTests
session.Disposed.ShouldBeFalse();
}
/// <summary>Verifies that ReapOnceAsync handles a session already removed from the registry without throwing.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReapOnceAsync_handles_already_removed_session()
{
@@ -65,6 +71,8 @@ public sealed class BrowseSessionReaperTests
session.Disposed.ShouldBeFalse();
}
/// <summary>Verifies that ReapOnceAsync continues processing remaining sessions when one session's dispose throws.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReapOnceAsync_continues_when_one_session_dispose_throws()
{
@@ -9,6 +9,7 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Browsing;
/// concurrent-registration behaviour.</summary>
public sealed class BrowseSessionRegistryTests
{
/// <summary>Verifies that a registered session can be retrieved by its token.</summary>
[Fact]
public void Register_then_TryGet_returns_session()
{
@@ -22,6 +23,7 @@ public sealed class BrowseSessionRegistryTests
got.ShouldBeSameAs((IBrowseSession)session);
}
/// <summary>Verifies that looking up an unknown token returns false.</summary>
[Fact]
public void TryGet_unknown_returns_false()
{
@@ -31,6 +33,7 @@ public sealed class BrowseSessionRegistryTests
got.ShouldBeNull();
}
/// <summary>Verifies that a removed session can no longer be retrieved.</summary>
[Fact]
public void TryRemove_then_TryGet_returns_false()
{
@@ -43,6 +46,8 @@ public sealed class BrowseSessionRegistryTests
registry.TryGet(session.Token, out _).ShouldBeFalse();
}
/// <summary>Verifies that concurrent registrations from many tasks are all visible in the snapshot.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Concurrent_Register_from_many_tasks_all_visible_in_Snapshot()
{
@@ -15,6 +15,8 @@ public sealed class BrowserSessionServiceTests
BrowseSessionRegistry registry, params IDriverBrowser[] browsers) =>
new(browsers, registry, NullLogger<BrowserSessionService>.Instance);
/// <summary>Verifies that OpenAsync returns Ok=false with a message when the driver type is unknown.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task OpenAsync_unknown_driver_type_returns_Ok_false_with_message()
{
@@ -29,6 +31,8 @@ public sealed class BrowserSessionServiceTests
result.Message!.ShouldContain("Unknown");
}
/// <summary>Verifies that OpenAsync returns a token and registers the session on the happy path.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task OpenAsync_happy_path_returns_token_and_registers()
{
@@ -50,6 +54,8 @@ public sealed class BrowserSessionServiceTests
registered.ShouldBeSameAs((IBrowseSession)session);
}
/// <summary>Verifies that OpenAsync swallows driver exceptions and returns Ok=false.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task OpenAsync_swallows_driver_throws_returns_Ok_false()
{
@@ -68,6 +74,8 @@ public sealed class BrowserSessionServiceTests
result.Message!.ShouldContain("boom");
}
/// <summary>Verifies that RootAsync throws BrowseSessionNotFoundException for an unknown token.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task RootAsync_unknown_token_throws_BrowseSessionNotFoundException()
{
@@ -78,6 +86,8 @@ public sealed class BrowserSessionServiceTests
() => service.RootAsync(Guid.NewGuid(), CancellationToken.None));
}
/// <summary>Verifies that RootAsync invokes the session Root method and returns its result.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task RootAsync_invokes_session_Root()
{
@@ -96,6 +106,8 @@ public sealed class BrowserSessionServiceTests
actual.ShouldBe(expected);
}
/// <summary>Verifies that RootAsync cancels the call when the per-call timeout elapses.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task RootAsync_enforces_PerCallTimeout()
{
@@ -118,6 +130,8 @@ public sealed class BrowserSessionServiceTests
sw.Elapsed.ShouldBeLessThan(TimeSpan.FromSeconds(35));
}
/// <summary>Verifies that CloseAsync removes the session from the registry and disposes it.</summary>
/// <returns>A task that represents the asynchronous test operation.</returns>
[Fact]
public async Task CloseAsync_removes_and_disposes_session()
{
@@ -11,7 +11,7 @@ internal sealed class FakeBrowseSession : IBrowseSession
/// <inheritdoc />
public Guid Token { get; } = Guid.NewGuid();
/// <summary>Mutable so tests can rewind the timestamp into the reaper's eviction window.</summary>
/// <inheritdoc />
public DateTime LastUsedUtc { get; set; } = DateTime.UtcNow;
/// <summary>True once <see cref="DisposeAsync"/> has run to completion.</summary>
@@ -40,7 +40,8 @@ internal sealed class FakeBrowseSession : IBrowseSession
public Task<IReadOnlyList<AttributeInfo>> AttributesAsync(string nodeId, CancellationToken ct)
=> AttributesHandler?.Invoke(nodeId, ct) ?? Task.FromResult<IReadOnlyList<AttributeInfo>>(Array.Empty<AttributeInfo>());
/// <inheritdoc />
/// <summary>Disposes the fake browse session asynchronously, recording completion or throwing if configured.</summary>
/// <returns>A completed value task.</returns>
public ValueTask DisposeAsync()
{
if (ThrowOnDispose) throw new InvalidOperationException("dispose-failed");
@@ -17,6 +17,7 @@ public sealed class DriverStatusSnapshotStoreTests
private static DriverHealthChanged Snap(string instance, string state = "Healthy") =>
new("MAIN", instance, state, null, null, 0, new DateTime(2026, 5, 29, 0, 0, 0, DateTimeKind.Utc));
/// <summary>Verifies that Upsert raises SnapshotChanged with the stored snapshot.</summary>
[Fact]
public void Upsert_raises_SnapshotChanged_with_the_stored_snapshot()
{
@@ -31,6 +32,7 @@ public sealed class DriverStatusSnapshotStoreTests
received[0].ShouldBeSameAs(snap);
}
/// <summary>Verifies that Upsert then TryGet returns the latest snapshot.</summary>
[Fact]
public void Upsert_then_TryGet_returns_the_latest_snapshot()
{
@@ -42,6 +44,7 @@ public sealed class DriverStatusSnapshotStoreTests
latest.State.ShouldBe("Degraded");
}
/// <summary>Verifies that an unsubscribed handler stops receiving events after removal.</summary>
[Fact]
public void Unsubscribed_handler_stops_receiving_after_removal()
{
@@ -21,6 +21,7 @@ public sealed class FocasDriverPageFormSerializationTests
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
};
/// <summary>Verifies that a round-trip serialization preserves all known FOCAS driver option fields.</summary>
[Fact]
public void RoundTrip_PreservesKnownFields()
{
@@ -76,6 +77,7 @@ public sealed class FocasDriverPageFormSerializationTests
back.Tags.ShouldBeEmpty();
}
/// <summary>Verifies that deserialization silently drops unknown fields without throwing.</summary>
[Fact]
public void Deserialize_DropsUnknownFields()
{
@@ -89,6 +91,7 @@ public sealed class FocasDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(18);
}
/// <summary>Verifies that the form model round-trip preserves all editable FOCAS driver option fields.</summary>
[Fact]
public void FormModel_RoundTrip_PreservesEditableFields()
{
@@ -140,6 +143,7 @@ public sealed class FocasDriverPageFormSerializationTests
roundTripped.FixedTree.TimerPollInterval.ShouldBe(TimeSpan.FromSeconds(45));
}
/// <summary>Verifies that a FocasDeviceRow round-trips correctly through its definition type.</summary>
[Fact]
public void DeviceRow_round_trips_through_definition()
{
@@ -155,6 +159,7 @@ public sealed class FocasDriverPageFormSerializationTests
back.DeviceName.ShouldBe("CNC1");
}
/// <summary>Verifies that FocasDeviceRow preserves unedited fields when converting to and from a definition.</summary>
[Fact]
public void DeviceRow_preserves_unedited_fields()
{
@@ -168,6 +173,7 @@ public sealed class FocasDriverPageFormSerializationTests
back.Series.ShouldBe(FocasCncSeries.Thirty_i);
}
/// <summary>Verifies that a FocasTagRow round-trips correctly through its definition type.</summary>
[Fact]
public void TagRow_round_trips_through_definition()
{
@@ -186,6 +192,7 @@ public sealed class FocasDriverPageFormSerializationTests
back.Writable.ShouldBeTrue();
}
/// <summary>Verifies that FocasTagRow preserves unedited fields when converting to a definition.</summary>
[Fact]
public void TagRow_preserves_unedited_fields()
{
@@ -200,6 +207,7 @@ public sealed class FocasDriverPageFormSerializationTests
back.WriteIdempotent.ShouldBeTrue();
}
/// <summary>Verifies that device row validation rejects a duplicate host address.</summary>
[Fact]
public void ValidateDeviceRow_rejects_duplicate_host()
{
@@ -208,6 +216,7 @@ public sealed class FocasDriverPageFormSerializationTests
.ShouldNotBeNull();
}
/// <summary>Verifies that tag row validation rejects a duplicate tag name.</summary>
[Fact]
public void ValidateTagRow_rejects_duplicate_name()
{
@@ -216,6 +225,7 @@ public sealed class FocasDriverPageFormSerializationTests
.ShouldNotBeNull();
}
/// <summary>Verifies that device and tag lists survive a full options serialization round-trip.</summary>
[Fact]
public void Device_and_tag_lists_survive_options_serialize_round_trip()
{
@@ -25,6 +25,7 @@ public sealed class GalaxyDriverPageFormSerializationTests
WriteIndented = false,
};
/// <summary>Verifies that a round-trip serialization preserves all known fields of GalaxyDriverOptions.</summary>
[Fact]
public void RoundTrip_PreservesKnownFields()
{
@@ -76,6 +77,7 @@ public sealed class GalaxyDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(45);
}
/// <summary>Verifies that deserialization silently drops unknown fields from the JSON input.</summary>
[Fact]
public void Deserialize_DropsUnknownFields()
{
@@ -15,6 +15,7 @@ public sealed class HistorianWonderwareDriverPageFormSerializationTests
WriteIndented = false,
};
/// <summary>Verifies that a round-trip serialization/deserialization preserves all known fields.</summary>
[Fact]
public void RoundTrip_PreservesKnownFields()
{
@@ -42,6 +43,7 @@ public sealed class HistorianWonderwareDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(25);
}
/// <summary>Verifies that null timeout values fall back to the expected defaults after deserialization.</summary>
[Fact]
public void RoundTrip_NullTimeouts_UsesDefaults()
{
@@ -59,6 +61,7 @@ public sealed class HistorianWonderwareDriverPageFormSerializationTests
back.EffectiveCallTimeout.ShouldBe(TimeSpan.FromSeconds(30));
}
/// <summary>Verifies that unknown JSON properties are silently ignored during deserialization.</summary>
[Fact]
public void Deserialize_DropsUnknownFields()
{
@@ -82,6 +85,7 @@ public sealed class HistorianWonderwareDriverPageFormSerializationTests
back.PipeName.ShouldBe("otopcua-historian");
}
/// <summary>Verifies that the form model FromRecord/ToRecord round-trip preserves all fields losslessly.</summary>
[Fact]
public void FormModel_RoundTrip_PreservesAllFields()
{
@@ -12,6 +12,7 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests;
/// </summary>
public sealed class InProcessBroadcasterTests
{
/// <summary>Verifies that Publish raises the Received event for all current subscribers.</summary>
[Fact]
public void Publish_raises_Received_for_all_current_subscribers()
{
@@ -27,6 +28,7 @@ public sealed class InProcessBroadcasterTests
b.ShouldBe(["evt-1"]);
}
/// <summary>Verifies that an unsubscribed handler stops receiving events after removal.</summary>
[Fact]
public void Unsubscribed_handler_stops_receiving()
{
@@ -42,6 +44,7 @@ public sealed class InProcessBroadcasterTests
received.ShouldBe(["first"]);
}
/// <summary>Verifies that Publish with no subscribers does not throw an exception.</summary>
[Fact]
public void Publish_with_no_subscribers_does_not_throw()
{
@@ -21,6 +21,7 @@ public sealed class ModbusDriverPageFormSerializationTests
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
};
/// <summary>Verifies that round-trip serialization preserves all known Modbus driver fields.</summary>
[Fact]
public void RoundTrip_PreservesKnownFields()
{
@@ -97,6 +98,7 @@ public sealed class ModbusDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(10);
}
/// <summary>Verifies that deserialization silently drops unknown Modbus driver fields.</summary>
[Fact]
public void Deserialize_DropsUnknownFields()
{
@@ -112,6 +114,7 @@ public sealed class ModbusDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(10);
}
/// <summary>Verifies that a tag row round-trips through its definition.</summary>
[Fact]
public void TagRow_round_trips_through_definition()
{
@@ -129,6 +132,7 @@ public sealed class ModbusDriverPageFormSerializationTests
back.Writable.ShouldBeTrue();
}
/// <summary>Verifies that the tag list survives a full options serialization round-trip.</summary>
[Fact]
public void Tag_list_survives_options_serialize_round_trip()
{
@@ -144,6 +148,7 @@ public sealed class ModbusDriverPageFormSerializationTests
back.Tags[0].Name.ShouldBe("A");
}
/// <summary>Verifies that tag row validation rejects a duplicate tag name.</summary>
[Fact]
public void ValidateRow_rejects_duplicate_name()
{
@@ -152,6 +157,7 @@ public sealed class ModbusDriverPageFormSerializationTests
.ShouldNotBeNull();
}
/// <summary>Verifies that converting a tag row to a definition preserves unedited fields.</summary>
[Fact]
public void ToDefinition_preserves_unedited_fields()
{
@@ -17,6 +17,7 @@ public sealed class OpcUaClientDriverPageFormSerializationTests
WriteIndented = false,
};
/// <summary>Verifies that a round-trip serialization preserves all known driver option fields.</summary>
[Fact]
public void RoundTrip_PreservesKnownFields()
{
@@ -68,6 +69,7 @@ public sealed class OpcUaClientDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(20);
}
/// <summary>Verifies that deserialization silently drops unknown fields.</summary>
[Fact]
public void Deserialize_DropsUnknownFields()
{
@@ -83,6 +85,7 @@ public sealed class OpcUaClientDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(20);
}
/// <summary>Verifies that the form model round-trip preserves all driver option fields.</summary>
[Fact]
public void FormModel_RoundTrip_PreservesAllFields()
{
@@ -156,6 +159,7 @@ public sealed class OpcUaClientDriverPageFormSerializationTests
result.ProbeTimeoutSeconds.ShouldBe(25);
}
/// <summary>Verifies that EndpointUrlRow.ToUrl trims leading and trailing whitespace.</summary>
[Fact]
public void EndpointUrlRow_FromUrl_ToUrl_Trims()
{
@@ -165,6 +169,7 @@ public sealed class OpcUaClientDriverPageFormSerializationTests
row.ToUrl().ShouldBe("opc.tcp://plc:4840");
}
/// <summary>Verifies that ValidateRow rejects a blank URL.</summary>
[Fact]
public void EndpointUrlRow_ValidateRow_RejectsBlank()
{
@@ -176,6 +181,7 @@ public sealed class OpcUaClientDriverPageFormSerializationTests
error.ShouldBe("URL is required.");
}
/// <summary>Verifies that ValidateRow rejects a URL with a non-opc.tcp scheme.</summary>
[Fact]
public void EndpointUrlRow_ValidateRow_RejectsNonOpcTcpScheme()
{
@@ -187,6 +193,7 @@ public sealed class OpcUaClientDriverPageFormSerializationTests
error.ShouldBe("Endpoint URL must start with opc.tcp://");
}
/// <summary>Verifies that ValidateRow rejects a duplicate URL.</summary>
[Fact]
public void EndpointUrlRow_ValidateRow_RejectsDuplicate()
{
@@ -204,6 +211,7 @@ public sealed class OpcUaClientDriverPageFormSerializationTests
error.ShouldContain("Duplicate endpoint");
}
/// <summary>Verifies that editing a row in-place does not flag it as a duplicate of itself.</summary>
[Fact]
public void EndpointUrlRow_ValidateRow_AllowsEditingRowInPlace()
{
@@ -220,6 +228,7 @@ public sealed class OpcUaClientDriverPageFormSerializationTests
error.ShouldBeNull();
}
/// <summary>Verifies that an endpoint URL list round-trips and preserves the original order.</summary>
[Fact]
public void EndpointUrls_ListRoundTrip_PreservesOrder()
{
@@ -6,6 +6,11 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
public sealed class AbLegacyAddressBuilderTests
{
/// <summary>Verifies that Build_Canonical returns the expected canonical address string for each file type.</summary>
/// <param name="fileType">The file type letter (e.g., N, B, F).</param>
/// <param name="fileNumber">The file number.</param>
/// <param name="element">The element index within the file.</param>
/// <param name="expected">The expected canonical address string.</param>
[Theory]
[InlineData("N", 7, 0, "N7:0")]
[InlineData("B", 3, 1, "B3:1")]
@@ -6,6 +6,10 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
public sealed class FocasAddressBuilderTests
{
/// <summary>Verifies that Build produces the canonical group:parameterId address string.</summary>
/// <param name="group">The FOCAS parameter group name.</param>
/// <param name="parameterId">The FOCAS parameter ID.</param>
/// <param name="expected">The expected canonical address string.</param>
[Theory]
[InlineData("axis", 5, "axis:5")]
[InlineData("spindle", 0, "spindle:0")]
@@ -6,6 +6,11 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
public sealed class HistorianWonderwareAddressBuilderTests
{
/// <summary>Verifies that Build produces the canonical address query string for various tag/mode/interval combinations.</summary>
/// <param name="tag">The tag name input.</param>
/// <param name="mode">The retrieval mode input.</param>
/// <param name="interval">The interval input.</param>
/// <param name="expected">The expected canonical address string.</param>
[Theory]
[InlineData("SysTimeHour", "Cyclic", 60, "SysTimeHour?mode=Cyclic&interval=60")]
[InlineData("ReactorTemp", "Last", 1, "ReactorTemp?mode=Last&interval=1")]
@@ -6,6 +6,11 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
public sealed class ModbusAddressBuilderTests
{
/// <summary>Verifies that Build produces canonical Modbus address strings for all supported register types.</summary>
/// <param name="type">The Modbus register type.</param>
/// <param name="offset">The register offset.</param>
/// <param name="length">The data length.</param>
/// <param name="expected">The expected canonical address string.</param>
[Theory]
[InlineData("Holding", 1, 1, "4x00001-1")]
[InlineData("Coil", 0, 1, "0x00000-1")]
@@ -15,6 +20,7 @@ public sealed class ModbusAddressBuilderTests
public void Build_Canonical(string type, int offset, int length, string expected)
=> ModbusAddressBuilder.Build(type, offset, length).ShouldBe(expected);
/// <summary>Verifies that Build falls back to the Holding register type for unknown type strings.</summary>
[Fact]
public void Build_UnknownType_FallsBackToHolding()
=> ModbusAddressBuilder.Build("Unknown", 1, 1).ShouldBe("4x00001-1");
@@ -6,6 +6,12 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
public sealed class S7AddressBuilderTests
{
/// <summary>Verifies that Build produces the canonical S7 address string for all supported areas and types.</summary>
/// <param name="area">The S7 memory area (DB / M / I / Q).</param>
/// <param name="dbNumber">The DB number (relevant only for the DB area).</param>
/// <param name="offset">The byte offset within the area.</param>
/// <param name="s7Type">The S7 data type qualifier (X / B / W / D / REAL).</param>
/// <param name="expected">The expected canonical address string.</param>
[Theory]
[InlineData("DB", 10, 20, "REAL", "DB10.DBD20:REAL")]
[InlineData("DB", 1, 0, "X", "DB1.DBX0.0:X")]
@@ -6,10 +6,12 @@ using ZB.MOM.WW.OtOpcUa.Core.Resilience;
public class ResilienceFormModelTests
{
/// <summary>Verifies that a blank form model serializes to null JSON.</summary>
[Fact]
public void Blank_form_serializes_to_null()
=> new ResilienceFormModel().ToJson().ShouldBeNull();
/// <summary>Verifies that a partial policy override round-trips correctly through JSON.</summary>
[Fact]
public void Partial_override_round_trips()
{
@@ -26,6 +28,7 @@ public class ResilienceFormModelTests
back.Policies["Write"].IsEmpty.ShouldBeTrue();
}
/// <summary>Verifies that malformed JSON input yields an empty model with no-error handling.</summary>
[Fact]
public void Malformed_json_yields_empty_model()
{
@@ -34,6 +37,7 @@ public class ResilienceFormModelTests
m.Policies["Read"].IsEmpty.ShouldBeTrue();
}
/// <summary>Verifies that JSON emitted by the form model can be parsed by the runtime resilience options parser.</summary>
[Fact]
public void Emitted_json_is_consumable_by_the_runtime_parser()
{
@@ -15,6 +15,7 @@ public sealed class S7DriverPageFormSerializationTests
WriteIndented = false,
};
/// <summary>Verifies that serializing and deserializing S7 driver options preserves all known fields.</summary>
[Fact]
public void RoundTrip_PreservesKnownFields()
{
@@ -54,6 +55,7 @@ public sealed class S7DriverPageFormSerializationTests
back.Tags.ShouldBeEmpty();
}
/// <summary>Verifies that deserializing JSON with unknown fields silently drops the unrecognized members.</summary>
[Fact]
public void Deserialize_DropsUnknownFields()
{
@@ -67,6 +69,7 @@ public sealed class S7DriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(12);
}
/// <summary>Verifies that the S7 form model round-trip preserves all editable fields including tags.</summary>
[Fact]
public void FormModel_RoundTrip_PreservesEditableFields()
{
@@ -122,6 +125,7 @@ public sealed class S7DriverPageFormSerializationTests
roundTripped.Tags[1].Writable.ShouldBeFalse();
}
/// <summary>Verifies that an S7 tag row round-trip preserves all editable fields.</summary>
[Fact]
public void S7TagRow_RoundTrip_PreservesEditableFields()
{
@@ -137,6 +141,7 @@ public sealed class S7DriverPageFormSerializationTests
back.StringLength.ShouldBe(80);
}
/// <summary>Verifies that unedited fields are carried through after an S7 tag row edit.</summary>
[Fact]
public void S7TagRow_CarriesThroughUneditedFields()
{
@@ -154,6 +159,7 @@ public sealed class S7DriverPageFormSerializationTests
back.WriteIdempotent.ShouldBeTrue();
}
/// <summary>Verifies that S7 tag row validation rejects duplicate tag names.</summary>
[Fact]
public void S7TagRow_ValidateRow_RejectsDuplicateNames()
{
@@ -180,6 +186,7 @@ public sealed class S7DriverPageFormSerializationTests
S7DriverPage.S7TagRow.ValidateRow(ok, all, editIndex: 1).ShouldBeNull();
}
/// <summary>Verifies that the tag list serialize round-trip preserves all tag definitions.</summary>
[Fact]
public void TagList_SerializeRoundTrip_PreservesTags()
{
@@ -14,6 +14,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
WriteIndented = false,
};
/// <summary>Verifies that serializing and deserializing TwinCAT driver options preserves all known fields.</summary>
[Fact]
public void RoundTrip_PreservesKnownFields()
{
@@ -51,6 +52,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
back.Tags.ShouldBeEmpty();
}
/// <summary>Verifies that deserializing JSON with unknown fields silently drops the unrecognized members.</summary>
[Fact]
public void Deserialize_DropsUnknownFields()
{
@@ -64,6 +66,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
back.ProbeTimeoutSeconds.ShouldBe(25);
}
/// <summary>Verifies that the form model round-trip preserves all editable fields.</summary>
[Fact]
public void FormModel_RoundTrip_PreservesEditableFields()
{
@@ -96,6 +99,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
roundTripped.ProbeTimeoutSeconds.ShouldBe(15);
}
/// <summary>Verifies that a device row round-trip preserves all editable fields.</summary>
[Fact]
public void DeviceRow_RoundTrip_PreservesEditableFields()
{
@@ -109,6 +113,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
back.DeviceName.ShouldBe("PLC1");
}
/// <summary>Verifies that unedited source fields are carried through after a device row edit.</summary>
[Fact]
public void DeviceRow_CarriesThroughUneditedSourceFields()
{
@@ -124,6 +129,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
back.DeviceName.ShouldBe("Renamed");
}
/// <summary>Verifies that device row validation rejects duplicate host addresses.</summary>
[Fact]
public void DeviceRow_ValidateRow_RejectsDuplicateHostAddress()
{
@@ -140,6 +146,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
error.ShouldContain("Duplicate");
}
/// <summary>Verifies that a tag row round-trip preserves all editable fields.</summary>
[Fact]
public void TagRow_RoundTrip_PreservesEditableFields()
{
@@ -156,6 +163,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
back.Writable.ShouldBeFalse();
}
/// <summary>Verifies that the unedited WriteIdempotent field is carried through after a tag row edit.</summary>
[Fact]
public void TagRow_CarriesThroughUneditedWriteIdempotent()
{
@@ -172,6 +180,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
back.WriteIdempotent.ShouldBeTrue();
}
/// <summary>Verifies that tag row validation rejects duplicate tag names (case-insensitive).</summary>
[Fact]
public void TagRow_ValidateRow_RejectsDuplicateName()
{
@@ -189,6 +198,7 @@ public sealed class TwinCATDriverPageFormSerializationTests
error.ShouldContain("Duplicate");
}
/// <summary>Verifies that ToOptions serializes device and tag lists correctly.</summary>
[Fact]
public void FormModel_ToOptions_SerializesDeviceAndTagLists()
{
@@ -5,6 +5,7 @@ namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests;
public sealed class _PlaceholderTests
{
/// <summary>Verifies the project compiles and the test runner can discover test methods.</summary>
[Fact]
public void ProjectCompilesAndTestRunnerDiscoversIt() => 1.ShouldBe(1);
}