using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.E2E; /// /// Test-only that records every Folder + Variable /// registration. Mirrors the v1 in-process address-space build so tests can assert on /// the same shape the legacy LmxNodeManager produced. /// public sealed class RecordingAddressSpaceBuilder : IAddressSpaceBuilder { public List Folders { get; } = new(); public List Variables { get; } = new(); public List Properties { get; } = new(); public List AlarmConditions { get; } = new(); public IAddressSpaceBuilder Folder(string browseName, string displayName) { Folders.Add(new RecordedFolder(browseName, displayName)); return this; // single flat builder for tests; nesting irrelevant for parity assertions } public IVariableHandle Variable(string browseName, string displayName, DriverAttributeInfo attributeInfo) { Variables.Add(new RecordedVariable(browseName, displayName, attributeInfo)); return new RecordedVariableHandle(attributeInfo.FullName, AlarmConditions); } public void AddProperty(string browseName, DriverDataType dataType, object? value) { Properties.Add(new RecordedProperty(browseName, dataType, value)); } public sealed record RecordedFolder(string BrowseName, string DisplayName); public sealed record RecordedVariable(string BrowseName, string DisplayName, DriverAttributeInfo AttributeInfo); public sealed record RecordedProperty(string BrowseName, DriverDataType DataType, object? Value); public sealed record RecordedAlarmCondition(string SourceNodeId, AlarmConditionInfo Info); public sealed record RecordedAlarmTransition(string SourceNodeId, AlarmEventArgs Args); /// /// Sink the tests assert on to verify the alarm event forwarder routed a transition /// to the correct source-node-id. One entry per . /// public List AlarmTransitions { get; } = new(); private sealed class RecordedVariableHandle : IVariableHandle { private readonly List _conditions; public string FullReference { get; } public RecordedVariableHandle(string fullReference, List conditions) { FullReference = fullReference; _conditions = conditions; } public IAlarmConditionSink MarkAsAlarmCondition(AlarmConditionInfo info) { _conditions.Add(new RecordedAlarmCondition(FullReference, info)); return new RecordingSink(FullReference); } private sealed class RecordingSink : IAlarmConditionSink { public string SourceNodeId { get; } public List Received { get; } = new(); public RecordingSink(string sourceNodeId) => SourceNodeId = sourceNodeId; public void OnTransition(AlarmEventArgs args) => Received.Add(args); } } }