diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Heidenhain.Tests/HeidenhainLiveIntegrationTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Heidenhain.Tests/HeidenhainLiveIntegrationTests.cs index 4ddff1680..46de2e751 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Heidenhain.Tests/HeidenhainLiveIntegrationTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Heidenhain.Tests/HeidenhainLiveIntegrationTests.cs @@ -86,6 +86,49 @@ public sealed class HeidenhainLiveIntegrationTests values[0].StatusCode.ShouldBe(HeidenhainStatus.Good); } + /// + /// Derived String leaves (family classification, pyLSV2 state names, tool axis name) — no extra wire request; + /// each is computed from a reply the session already reads. + /// + [Fact] + public async Task Real_control_derived_name_leaves() + { + Assert.SkipWhen(string.IsNullOrWhiteSpace(Host), "HEIDENHAIN_LSV2_HOST not set — real-controller gate skipped."); + var ct = TestContext.Current.CancellationToken; + var tags = new[] + { + TestTags.Raw("Controller/Model"), TestTags.Raw("Controller/Family"), + TestTags.Raw("Status/ExecutionState"), TestTags.Raw("Status/ExecutionStateName"), + TestTags.Raw("Status/ProgramState"), TestTags.Raw("Status/ProgramStateName"), + TestTags.Raw("Tool/AxisCode"), TestTags.Raw("Tool/AxisName"), + }; + var options = new HeidenhainDriverOptions + { + Devices = [new HeidenhainDeviceOptions { Host = Host!, Port = Port, DeviceName = "dev1" }], + RawTags = tags, + Access = new HeidenhainAccessOptions { InspectPassword = Environment.GetEnvironmentVariable("OTOPCUA_HEIDENHAIN_INSPECT_PASSWORD") is { Length: > 0 } ? "env:OTOPCUA_HEIDENHAIN_INSPECT_PASSWORD" : null }, + }; + await using var driver = new HeidenhainDriver(options, "live"); + await driver.InitializeAsync("{}", ct); + await driver.SubscribeAsync(tags.Select(t => t.RawPath).ToList(), TimeSpan.FromSeconds(1), ct); + var deadline = DateTime.UtcNow.AddSeconds(30); + IReadOnlyList values; + do + { + await Task.Delay(500, ct); + values = await driver.ReadAsync(tags.Select(t => t.RawPath).ToList(), ct); + } while ((values[1].StatusCode != HeidenhainStatus.Good || values[3].StatusCode != HeidenhainStatus.Good) && DateTime.UtcNow < deadline); + + for (var i = 0; i < tags.Length; i++) + TestContext.Current.SendDiagnosticMessage($"{tags[i].RawPath} = {values[i].Value} (0x{values[i].StatusCode:X8})"); + values[1].StatusCode.ShouldBe(HeidenhainStatus.Good); + values[1].Value.ShouldNotBe("Unknown"); + values[3].StatusCode.ShouldBe(HeidenhainStatus.Good); + values[5].StatusCode.ShouldBe(HeidenhainStatus.Good); + // A name leaf never disagrees with its raw leaf's quality. + values[7].StatusCode.ShouldBe(values[6].StatusCode); + } + /// #867: integer tool leaves must reach clients with their declared runtime type, not Double. [Fact] public async Task Real_control_tool_leaves_keep_integer_types()