feat(focas): resolve equipment-tag refs (read + write) via EquipmentTagRefResolver
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.FOCAS;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests;
|
||||
|
||||
[Trait("Category", "Unit")]
|
||||
public class FocasEquipmentTagTests
|
||||
{
|
||||
[Fact]
|
||||
public void Parses_equipment_tagconfig_into_a_transient_definition()
|
||||
{
|
||||
var json = """{"deviceHostAddress":"focas://10.0.0.5:8193","address":"R100","dataType":"Byte"}""";
|
||||
FocasEquipmentTagParser.TryParse(json, out var def).ShouldBeTrue();
|
||||
def!.Name.ShouldBe(json);
|
||||
def.DeviceHostAddress.ShouldBe("focas://10.0.0.5:8193");
|
||||
def.Address.ShouldBe("R100");
|
||||
def.DataType.ShouldBe(FocasDataType.Byte);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Rejects_a_non_address_blob()
|
||||
=> FocasEquipmentTagParser.TryParse("""{"FullName":"x"}""", out _).ShouldBeFalse();
|
||||
|
||||
[Fact]
|
||||
public void Rejects_garbage()
|
||||
=> FocasEquipmentTagParser.TryParse("not json", out _).ShouldBeFalse();
|
||||
|
||||
[Fact]
|
||||
public void Rejects_address_as_a_json_number()
|
||||
=> FocasEquipmentTagParser.TryParse(
|
||||
"""{"address":100,"dataType":"Int32"}""", out _).ShouldBeFalse();
|
||||
|
||||
[Fact]
|
||||
public void Rejects_a_blank_address()
|
||||
=> FocasEquipmentTagParser.TryParse(
|
||||
"""{"address":" ","dataType":"Int32"}""", out _).ShouldBeFalse();
|
||||
|
||||
// FOCAS's only mandatory address field is the canonical Address STRING (no narrow numeric
|
||||
// TagConfig field like Modbus's ushort register address), so the Modbus "numeric out-of-range"
|
||||
// rejection case has no analog here — covered instead by the json-number + blank-address cases.
|
||||
|
||||
/// <summary>
|
||||
/// End-to-end driver-level proof: a FOCAS driver with NO authored tags can still read an
|
||||
/// equipment-tag ref (the raw TagConfig JSON) — the resolver parses it into a transient
|
||||
/// definition and the read goes to the wire instead of returning BadNodeIdUnknown.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Driver_resolves_an_equipment_ref_and_reads_instead_of_BadNodeIdUnknown()
|
||||
{
|
||||
var json = """{"deviceHostAddress":"focas://10.0.0.5:8193","address":"R100","dataType":"Byte"}""";
|
||||
var factory = new FakeFocasClientFactory { Customise = () => new FakeFocasClient { Values = { ["R100"] = (sbyte)42 } } };
|
||||
var drv = new FocasDriver(new FocasDriverOptions
|
||||
{
|
||||
Devices = [new FocasDeviceOptions("focas://10.0.0.5:8193")],
|
||||
Tags = [],
|
||||
Probe = new FocasProbeOptions { Enabled = false },
|
||||
}, "focas-eq", factory);
|
||||
await drv.InitializeAsync("{}", CancellationToken.None);
|
||||
|
||||
var r = await drv.ReadAsync([json], CancellationToken.None);
|
||||
|
||||
r[0].StatusCode.ShouldBe(FocasStatusMapper.Good);
|
||||
r[0].StatusCode.ShouldNotBe(FocasStatusMapper.BadNodeIdUnknown);
|
||||
r[0].Value.ShouldBe((sbyte)42);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user