using RioJoy.Core.Plasma; using RioJoy.Core.Tests.Serial; using Xunit; namespace RioJoy.Core.Tests.Plasma; public class PlasmaDisplayTests { private static byte[][] PosTextChunks(string text, byte x = 0, byte y = 0, byte attr = 0, byte font = 0) { (byte rx, byte ry, byte rfont, int len) = PlasmaCommands.ResolvePosText(text, x, y, font); return new[] { PlasmaCommands.CursorX(rx), PlasmaCommands.CursorY(ry), PlasmaCommands.FontAttr(attr), PlasmaCommands.Font(rfont), PlasmaCommands.Text(text[..len]), }; } [Fact] public async Task PosTextAsync_EmitsThePosTextSequenceInOrder() { var transport = new FakeTransport(); var display = new PlasmaDisplay(transport); await display.PosTextAsync("VIPER 1-1").WithTimeout(); foreach (byte[] expected in PosTextChunks("VIPER 1-1")) Assert.Equal(expected, await transport.NextWriteAsync()); } [Fact] public async Task PosTextAsync_EmptyText_WritesNothing() { var transport = new FakeTransport(); var display = new PlasmaDisplay(transport); await display.PosTextAsync("").WithTimeout(); Assert.False(transport.Writes.TryRead(out _)); } [Fact] public async Task ClearAsync_WritesTheClearCommand() { var transport = new FakeTransport(); var display = new PlasmaDisplay(transport); await display.ClearAsync().WithTimeout(); Assert.Equal(PlasmaCommands.Clear(), await transport.NextWriteAsync()); } [Fact] public async Task RowAsync_WritesOneGraphicsRowCommand() { var transport = new FakeTransport(); var display = new PlasmaDisplay(transport); var row = new byte[16]; row[3] = 0xF0; await display.RowAsync(12, row).WithTimeout(); Assert.Equal(PlasmaCommands.GraphicsRow(12, row), await transport.NextWriteAsync()); } [Fact] public async Task PosTextAsync_ConcurrentCalls_DoNotInterleave() { // Without the write lock, B's cursor/font fragments land between A's five // writes and corrupt the ESC stream. Gate A's first write so B has every // chance to sneak in, then assert the ten writes arrive as A's five // followed by B's five. var transport = new GatedTransport(); var display = new PlasmaDisplay(transport); Task a = display.PosTextAsync("AAAA"); Task b = display.PosTextAsync("BBBB"); transport.Open(); await Task.WhenAll(a, b).WithTimeout(); var writes = new List(); for (int i = 0; i < 10; i++) writes.Add(await transport.NextWriteAsync()); byte[][] expected = PosTextChunks("AAAA").Concat(PosTextChunks("BBBB")).ToArray(); for (int i = 0; i < expected.Length; i++) Assert.Equal(expected[i], writes[i]); } }