using Opc.Ua; using ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Adapters; namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests; /// /// M2.4 (#8) regression: standard OPC UA A&C events carry an event-type /// (e.g. i=9341 for ExclusiveLevelAlarmType), but the /// client-side conditionFilter gate — and the server-side WhereClause — both key off /// the friendly type names in . /// bridges the two by resolving the /// event-type NodeId back to its friendly name (NodeId-string fallback for custom /// types), so a friendly-name filter actually matches the events the server delivers. /// public class RealOpcUaClientAlarmFilterTests { [Fact] public void ResolveAlarmTypeName_KnownStandardNodeId_ReturnsFriendlyName() { // The well-known NodeId for ExclusiveLevelAlarmType (i=9341) must resolve to // the friendly name the conditionFilter/WhereClause use. var resolved = RealOpcUaClient.ResolveAlarmTypeName(ObjectTypeIds.ExclusiveLevelAlarmType); Assert.Equal("ExclusiveLevelAlarmType", resolved); } [Fact] public void ResolveAlarmTypeName_DiscreteAlarmNodeId_ReturnsFriendlyName() { var resolved = RealOpcUaClient.ResolveAlarmTypeName(ObjectTypeIds.DiscreteAlarmType); Assert.Equal("DiscreteAlarmType", resolved); } [Fact] public void ResolveAlarmTypeName_UnknownCustomNodeId_ReturnsNodeIdString() { // A vendor/custom subtype not in KnownConditionTypeIds: we cannot map it to a // friendly name, so we fall back to its NodeId string. This is consistent — // the WhereClause is also omitted for unknown names, so the client gate matches // the NodeId string, which is the only thing such a filter could carry. var custom = new NodeId(987654u, 7); var resolved = RealOpcUaClient.ResolveAlarmTypeName(custom); Assert.Equal(custom.ToString(), resolved); } [Fact] public void ResolveAlarmTypeName_Null_ReturnsEmptyString() { Assert.Equal("", RealOpcUaClient.ResolveAlarmTypeName(null)); } [Fact] public void InverseMap_RoundTrips_EveryKnownConditionType() { // The friendly→NodeId map (KnownConditionTypeIds) and the NodeId→friendly map // are derived from a single source of truth, so they must round-trip for every // entry — guards against the two maps drifting apart. foreach (var (friendlyName, nodeId) in RealOpcUaClient.KnownConditionTypeIds) { var resolved = RealOpcUaClient.ResolveAlarmTypeName(nodeId); Assert.Equal(friendlyName, resolved); } } }