using System.IO.Pipelines; namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests; /// /// Bidirectional in-memory stream pair for IPC tests. Two System.IO.Pipelines.Pipe /// instances — one per direction — exposed as endpoints /// via PipeReader.AsStream / PipeWriter.AsStream. Lets the test set up a /// FocasIpcClient on one end and a minimal fake server loop on the other without /// standing up a real named pipe. /// internal sealed class IpcLoopback : IAsyncDisposable { public Stream ClientSide { get; } public Stream ServerSide { get; } public IpcLoopback() { var clientToServer = new Pipe(); var serverToClient = new Pipe(); ClientSide = new DuplexPipeStream(serverToClient.Reader.AsStream(), clientToServer.Writer.AsStream()); ServerSide = new DuplexPipeStream(clientToServer.Reader.AsStream(), serverToClient.Writer.AsStream()); } public async ValueTask DisposeAsync() { await ClientSide.DisposeAsync(); await ServerSide.DisposeAsync(); } private sealed class DuplexPipeStream(Stream read, Stream write) : Stream { public override bool CanRead => true; public override bool CanWrite => true; public override bool CanSeek => false; public override long Length => throw new NotSupportedException(); public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } public override int Read(byte[] buffer, int offset, int count) => read.Read(buffer, offset, count); public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken ct) => read.ReadAsync(buffer, offset, count, ct); public override ValueTask ReadAsync(Memory buffer, CancellationToken ct = default) => read.ReadAsync(buffer, ct); public override void Write(byte[] buffer, int offset, int count) => write.Write(buffer, offset, count); public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken ct) => write.WriteAsync(buffer, offset, count, ct); public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken ct = default) => write.WriteAsync(buffer, ct); public override void Flush() => write.Flush(); public override Task FlushAsync(CancellationToken ct) => write.FlushAsync(ct); public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); public override void SetLength(long value) => throw new NotSupportedException(); protected override void Dispose(bool disposing) { if (disposing) { read.Dispose(); write.Dispose(); } base.Dispose(disposing); } } }