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 b0a9c4522..020425a31 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
@@ -85,4 +85,38 @@ public sealed class HeidenhainLiveIntegrationTests
TestContext.Current.SendDiagnosticMessage($"{tags[i].RawPath} = {values[i].Value} (0x{values[i].StatusCode:X8})");
values[0].StatusCode.ShouldBe(HeidenhainStatus.Good);
}
+
+ /// #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()
+ {
+ Assert.SkipWhen(string.IsNullOrWhiteSpace(Host), "HEIDENHAIN_LSV2_HOST not set — real-controller gate skipped.");
+ var ct = TestContext.Current.CancellationToken;
+ var tags = new[] { TestTags.Raw("Tool/Number"), TestTags.Raw("Tool/Index"), TestTags.Raw("Tool/AxisCode") };
+ 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.Any(v => v.StatusCode != HeidenhainStatus.Good) && DateTime.UtcNow < deadline);
+
+ var expected = new[] { typeof(long), typeof(int), typeof(int) };
+ for (var i = 0; i < tags.Length; i++)
+ {
+ TestContext.Current.SendDiagnosticMessage($"{tags[i].RawPath} = {values[i].Value} ({values[i].Value?.GetType().Name}) (0x{values[i].StatusCode:X8})");
+ if (values[i].StatusCode == HeidenhainStatus.Good)
+ values[i].Value!.GetType().ShouldBe(expected[i]);
+ }
+ values.Count(v => v.StatusCode == HeidenhainStatus.Good).ShouldBeGreaterThan(0);
+ }
}