using ZB.MOM.WW.OtOpcUa.Driver.TwinCAT; namespace ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests; internal class FakeTwinCATClient : ITwinCATClient { public bool IsConnected { get; private set; } public int ConnectCount { get; private set; } public int DisposeCount { get; private set; } public bool ThrowOnConnect { get; set; } public bool ThrowOnRead { get; set; } public bool ThrowOnWrite { get; set; } public bool ThrowOnProbe { get; set; } public Exception? Exception { get; set; } public Dictionary Values { get; } = new(StringComparer.OrdinalIgnoreCase); public Dictionary ReadStatuses { get; } = new(StringComparer.OrdinalIgnoreCase); public Dictionary WriteStatuses { get; } = new(StringComparer.OrdinalIgnoreCase); public List<(string symbol, TwinCATDataType type, int? bit, object? value)> WriteLog { get; } = new(); public bool ProbeResult { get; set; } = true; public virtual Task ConnectAsync(TwinCATAmsAddress address, TimeSpan timeout, CancellationToken ct) { ConnectCount++; if (ThrowOnConnect) throw Exception ?? new InvalidOperationException(); IsConnected = true; return Task.CompletedTask; } public virtual Task<(object? value, uint status)> ReadValueAsync( string symbolPath, TwinCATDataType type, int? bitIndex, CancellationToken ct) { if (ThrowOnRead) throw Exception ?? new InvalidOperationException(); var status = ReadStatuses.TryGetValue(symbolPath, out var s) ? s : TwinCATStatusMapper.Good; var value = Values.TryGetValue(symbolPath, out var v) ? v : null; return Task.FromResult((value, status)); } public virtual Task WriteValueAsync( string symbolPath, TwinCATDataType type, int? bitIndex, object? value, CancellationToken ct) { if (ThrowOnWrite) throw Exception ?? new InvalidOperationException(); WriteLog.Add((symbolPath, type, bitIndex, value)); Values[symbolPath] = value; var status = WriteStatuses.TryGetValue(symbolPath, out var s) ? s : TwinCATStatusMapper.Good; return Task.FromResult(status); } public virtual Task ProbeAsync(CancellationToken ct) { if (ThrowOnProbe) return Task.FromResult(false); return Task.FromResult(ProbeResult); } public virtual void Dispose() { DisposeCount++; IsConnected = false; } } internal sealed class FakeTwinCATClientFactory : ITwinCATClientFactory { public List Clients { get; } = new(); public Func? Customise { get; set; } public ITwinCATClient Create() { var client = Customise?.Invoke() ?? new FakeTwinCATClient(); Clients.Add(client); return client; } }