using ZB.MOM.WW.LmxProxy.Client.Domain; namespace ZB.MOM.WW.LmxProxy.Client.Tests.Fakes; /// /// Hand-written fake implementation of ILmxProxyClient for unit testing streaming extensions. /// internal class FakeLmxProxyClient : ILmxProxyClient { public TimeSpan DefaultTimeout { get; set; } = TimeSpan.FromSeconds(30); // Track calls public List> ReadBatchCalls { get; } = []; public List> WriteBatchCalls { get; } = []; public List> SubscribeCalls { get; } = []; // Configurable responses public Func, CancellationToken, Task>>? ReadBatchHandler { get; set; } public Exception? ReadBatchExceptionToThrow { get; set; } public int ReadBatchExceptionCount { get; set; } private int _readBatchCallCount; // Subscription support public Action? CapturedOnUpdate { get; private set; } public Action? CapturedOnError { get; private set; } public Task ConnectAsync(CancellationToken cancellationToken = default) => Task.CompletedTask; public Task DisconnectAsync() => Task.CompletedTask; public Task IsConnectedAsync() => Task.FromResult(true); public Task ReadAsync(string address, CancellationToken cancellationToken = default) => Task.FromResult(new Vtq(null, DateTime.UtcNow, Quality.Good)); public Task> ReadBatchAsync(IEnumerable addresses, CancellationToken cancellationToken = default) { var addressList = addresses.ToList(); ReadBatchCalls.Add(addressList); _readBatchCallCount++; if (ReadBatchExceptionToThrow is not null && _readBatchCallCount <= ReadBatchExceptionCount) throw ReadBatchExceptionToThrow; if (ReadBatchHandler is not null) return ReadBatchHandler(addressList, cancellationToken); var result = new Dictionary(); foreach (var addr in addressList) result[addr] = new Vtq(42.0, DateTime.UtcNow, Quality.Good); return Task.FromResult>(result); } public Task WriteAsync(string address, TypedValue value, CancellationToken cancellationToken = default) => Task.CompletedTask; public Task WriteBatchAsync(IDictionary values, CancellationToken cancellationToken = default) { WriteBatchCalls.Add(new Dictionary(values)); return Task.CompletedTask; } public Task WriteBatchAndWaitAsync( IDictionary values, string flagTag, TypedValue flagValue, int timeoutMs = 5000, int pollIntervalMs = 100, CancellationToken cancellationToken = default) => Task.FromResult(new WriteBatchAndWaitResponse { Success = true }); public Task SubscribeAsync( IEnumerable addresses, Action onUpdate, Action? onStreamError = null, CancellationToken cancellationToken = default) { SubscribeCalls.Add(addresses); CapturedOnUpdate = onUpdate; CapturedOnError = onStreamError; return Task.FromResult(new FakeSubscription()); } public Task CheckApiKeyAsync(string apiKey, CancellationToken cancellationToken = default) => Task.FromResult(new LmxProxyClient.ApiKeyInfo { IsValid = true }); public Dictionary GetMetrics() => []; public void Dispose() { } public ValueTask DisposeAsync() => ValueTask.CompletedTask; private class FakeSubscription : LmxProxyClient.ISubscription { public void Dispose() { } public Task DisposeAsync() => Task.CompletedTask; } }