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()