Files
riojoy/tests/RioJoy.Core.Tests/Plasma/PlasmaDisplayTests.cs
T
CydandClaude Fable 5 44b636ddd3 plasma: ESC P bitmap rows through the feedback endpoint (plasma row)
PlasmaCommands.GraphicsWrite/GraphicsRow port the display firmware graphics
command (ESC P s y x w h, MSB-left); PlasmaDisplay.RowAsync writes a locked
whole-row update; the line protocol gains `plasma row <y> <hex32>`. The
router plasma slot becomes a bounded FIFO queue: rows stream in order (a
frame must not tear), texts still coalesce to the newest, clear flushes, cap
128 with counted drops. Docs updated; 442 tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 20:45:38 -05:00

93 lines
2.9 KiB
C#

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<byte[]>();
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]);
}
}