Files
lmxopcua/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/TwinCATSumReadConstructionTests.cs
T
Joseph Doherty 664ff75ee2 fix(twincat): #645 live gate — sum-read never worked on hardware; TC2 diagnostics fallback
Read-only live gate on Elma presses Z35474 (TC3 3.1.4024) and Z34834 (TC2 2.11):

- Sum-read: every chunk came back BadCommunicationError. Beckhoff's
  SumRead(IList<IgIoSumReadEntity>) ctor casts to IList<SumDataEntity>, which
  throws InvalidCastException for a List<> (only an array survives via
  covariance). The fake-client tests never built a real SumRead. New
  AdsTwinCATClient.CreateSumRead passes an array; TwinCATSumReadConstructionTests
  pins it (red on the List form) plus a falsifiability control on the library.
  After the fix: 59 tags, status identical everywhere, values identical on every
  non-moving tag, ~0.35-0.66 s vs ~2.7 s per poll; TC2 CE 2.11 answers sum reads.
- An unexpected sum chunk failure now logs one Warning per device (it was
  invisible: the health message was overwritten by the next good read).
- Diagnostics: TC2 has no TwinCAT_SystemInfoVarList; fall back to .SYSTEMINFO /
  .SYSTEMTASKINFOARR[1] once the TC3 name answers not-found (live: all six keys).
- #612 browse: Flat verified on TC3 (10,770 leaves; VirtualTree 1,459 strict
  subset) — comment and docs updated, no load-mode option needed.

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
2026-10-08 21:17:44 -04:00

42 lines
1.9 KiB
C#

using Shouldly;
using TwinCAT.Ads;
using TwinCAT.Ads.SumCommand;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.TwinCAT;
namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests;
/// <summary>
/// hw2 live gate (2026-10-08, TC3 Z35474): every ADS sum-read chunk failed with
/// <see cref="InvalidCastException"/> thrown by Beckhoff's own <see cref="SumRead"/> constructor, because the
/// <c>IList&lt;IgIoSumReadEntity&gt;</c> overload casts its argument to <c>IList&lt;SumDataEntity&gt;</c> — which
/// works for an array (covariance) and not for a <c>List&lt;IgIoSumReadEntity&gt;</c>. The driver turned it into
/// <c>BadCommunicationError</c> for every batched tag on every poll. The fake client never builds a real
/// <see cref="SumRead"/>, so these tests construct one directly; the constructor does no I/O, so an unconnected
/// <see cref="AdsClient"/> is enough.
/// </summary>
[Trait("Category", "Unit")]
public sealed class TwinCATSumReadConstructionTests
{
[Fact]
public void CreateSumRead_builds_a_real_Beckhoff_sum_command_without_a_cast_failure()
{
using var client = new AdsClient();
var sum = AdsTwinCATClient.CreateSumRead(client, [(0x4040u, 0x10u, 2), (0x4040u, 0x20u, 4), (0x4020u, 0x0u, 81)]);
sum.ShouldNotBeNull();
}
[Fact]
public void The_Beckhoff_list_overload_really_throws_for_a_List_which_is_why_CreateSumRead_passes_an_array()
{
// Falsifiability control: if a future Beckhoff release fixes the cast, this test goes red and the remark
// on CreateSumRead can be retired — but the array form keeps working either way.
using var client = new AdsClient();
var list = new List<IgIoSumReadEntity> { new(0x4040, 0x10, 2), new(0x4040, 0x20, 4) };
Should.Throw<InvalidCastException>(() => new SumRead(client, list, SumCommandErrorStrategy.Relaxed));
}
}