using System.Text.Json; using NucleicBroker; namespace NucleicBroker.Tests; public sealed class OutboundWriterTests { [Fact] public async Task PreservesEnqueueOrderAcrossKinds() { var captured = new StringWriter(); var writer = new OutboundWriter(captured); writer.EnqueueJson("""{"a":1}"""); writer.EnqueueProcOutput(1, stderr: false, "one"u8); writer.EnqueueProcOutput(1, stderr: false, "two"u8); writer.EnqueueJson("""{"b":2}"""); await writer.CompleteAsync(); var lines = captured.ToString().Split('\n', StringSplitOptions.RemoveEmptyEntries); Assert.Equal("""{"a":1}""", lines[0]); Assert.Equal("""{"b":2}""", lines[^1]); // The two same-stream chunks arrive between the json lines, concatenated in order — // as ONE notification when the drain saw both queued, as two otherwise. Either way // the decoded byte stream is identical. var decoded = string.Concat(lines[1..^1].Select(l => { var note = JsonDocument.Parse(l).RootElement; Assert.Equal("proc.stdout", note.GetProperty("method").GetString()); return System.Text.Encoding.UTF8.GetString( Convert.FromBase64String(note.GetProperty("params").GetProperty("b64").GetString()!)); })); Assert.Equal("onetwo", decoded); } [Fact] public async Task StderrAndStdoutChunksNeverMerge() { var captured = new StringWriter(); var writer = new OutboundWriter(captured); writer.EnqueueProcOutput(1, stderr: false, "out"u8); writer.EnqueueProcOutput(1, stderr: true, "err"u8); await writer.CompleteAsync(); var methods = captured.ToString().Split('\n', StringSplitOptions.RemoveEmptyEntries) .Select(l => JsonDocument.Parse(l).RootElement.GetProperty("method").GetString()) .ToList(); Assert.Equal(["proc.stdout", "proc.stderr"], methods); } }