using System.Threading.Channels; using RioJoy.Core.Serial; namespace RioJoy.Core.Tests.Serial; /// /// In-memory for driving /// in tests: enqueue inbound chunks, inspect outbound writes. /// internal sealed class FakeTransport : IRioTransport { private readonly Channel _incoming = Channel.CreateUnbounded(); private readonly Channel _writes = Channel.CreateUnbounded(); public string Description => "fake"; /// Outbound writes, in order. Each call to WriteAsync yields one item. public ChannelReader Writes => _writes.Reader; /// Queue an inbound chunk for the receive loop to read. public void Enqueue(params byte[] data) => _incoming.Writer.TryWrite(data); /// Signal that no more inbound data will arrive (transport closed). public void CompleteIncoming() => _incoming.Writer.TryComplete(); public async Task ReadAsync(byte[] buffer, CancellationToken cancellationToken) { while (await _incoming.Reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false)) { if (_incoming.Reader.TryRead(out byte[]? chunk)) { Array.Copy(chunk, buffer, chunk.Length); return chunk.Length; } } return 0; // completed } public Task WriteAsync(byte[] data, CancellationToken cancellationToken) { _writes.Writer.TryWrite((byte[])data.Clone()); return Task.CompletedTask; } /// Read the next outbound write, failing if none arrives in time. public async Task NextWriteAsync(TimeSpan? timeout = null) { using var cts = new CancellationTokenSource(timeout ?? TimeSpan.FromSeconds(5)); return await _writes.Reader.ReadAsync(cts.Token).ConfigureAwait(false); } public void Dispose() { } }