using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy; namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests; internal class FakeAbLegacyTag : IAbLegacyTagRuntime { public AbLegacyTagCreateParams CreationParams { get; } public object? Value { get; set; } public int Status { get; set; } public bool ThrowOnInitialize { get; set; } public bool ThrowOnRead { get; set; } public bool ThrowOnWrite { get; set; } public Exception? Exception { get; set; } public int InitializeCount { get; private set; } public int ReadCount { get; private set; } public int WriteCount { get; private set; } public bool Disposed { get; private set; } public FakeAbLegacyTag(AbLegacyTagCreateParams p) => CreationParams = p; public virtual Task InitializeAsync(CancellationToken ct) { InitializeCount++; if (ThrowOnInitialize) throw Exception ?? new InvalidOperationException(); return Task.CompletedTask; } public virtual Task ReadAsync(CancellationToken ct) { ReadCount++; if (ThrowOnRead) throw Exception ?? new InvalidOperationException(); return Task.CompletedTask; } public virtual Task WriteAsync(CancellationToken ct) { WriteCount++; if (ThrowOnWrite) throw Exception ?? new InvalidOperationException(); return Task.CompletedTask; } public virtual int GetStatus() => Status; public int? LastDecodeBitIndex { get; private set; } public AbLegacyDataType? LastDecodeType { get; private set; } public virtual object? DecodeValue(AbLegacyDataType type, int? bitIndex) { LastDecodeType = type; LastDecodeBitIndex = bitIndex; // If the test seeded a parent-word value (ushort/short/int) and the driver asked for a // specific status bit, mask it out so we can assert the correct bit reaches the client. if (bitIndex is int bit && Value is not null and not bool) { try { var word = Convert.ToInt32(Value); return ((word >> bit) & 1) != 0; } catch (Exception ex) when (ex is FormatException or InvalidCastException) { } } return Value; } public virtual void EncodeValue(AbLegacyDataType type, int? bitIndex, object? value) => Value = value; public virtual void Dispose() => Disposed = true; } internal sealed class FakeAbLegacyTagFactory : IAbLegacyTagFactory { public Dictionary Tags { get; } = new(StringComparer.OrdinalIgnoreCase); public Func? Customise { get; set; } public IAbLegacyTagRuntime Create(AbLegacyTagCreateParams p) { var fake = Customise?.Invoke(p) ?? new FakeAbLegacyTag(p); Tags[p.TagName] = fake; return fake; } }