Files
VRIO/tests/VPlasma.Core.Tests/VPlasmaPipeServiceTests.cs
T
CydandClaude Fable 5 697cf3129b Pipe endpoints join the connection pickers; no more COM11/COM12 auto-bind
Each device row now serves one endpoint at a time, picked from a list of
pipe:vrio / pipe:vplasma (first, default) plus the machine's COM ports —
nothing opens automatically at startup. The pipe services gained an
IsListening property and are started/stopped by the row's Open/Close
button instead of running for the whole app lifetime, which also retires
the dual-transport warning. Status line shows the active endpoint;
OFFLINE when none. Standalone vPLASMA is unchanged (hardwired COM12 +
permanent pipe). Also fixes the xUnit1031 warnings in the plasma pipe
tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 23:17:34 -05:00

100 lines
3.2 KiB
C#

using System.Diagnostics;
using System.IO.Pipes;
using VPlasma.Core.Device;
using Xunit;
namespace VPlasma.Core.Tests;
public class VPlasmaPipeServiceTests
{
private static string UniqueName() => $"vplasma-test-{Guid.NewGuid():N}";
private static void WaitFor(Func<bool> condition, int timeoutMs = 2000)
{
var clock = Stopwatch.StartNew();
while (!condition())
{
Assert.True(clock.ElapsedMilliseconds < timeoutMs, "timed out waiting for a condition");
Thread.Sleep(10);
}
}
private static NamedPipeClientStream Connect(string name)
{
var pipe = new NamedPipeClientStream(".", name, PipeDirection.InOut, PipeOptions.Asynchronous);
var clock = Stopwatch.StartNew();
while (true)
{
try
{
pipe.Connect(200);
return pipe;
}
catch (Exception ex) when (ex is IOException or TimeoutException)
{
if (clock.ElapsedMilliseconds >= 3000)
throw;
Thread.Sleep(25);
}
}
}
[Fact]
public void Framed_text_reaches_the_display_and_lines_are_ignored()
{
string name = UniqueName();
var device = new VPlasmaDevice();
using var service = new VPlasmaPipeService(device, name);
service.Start();
using var client = Connect(name);
var hello = new byte[2];
Assert.Equal(1, client.Read(hello, 0, 1)); // on-connect lines frame,
Assert.Equal(1, client.Read(hello, 1, 1)); // possibly split
Assert.Equal(new byte[] { 0x01, 0x03 }, hello); // DTR+RTS: display present
// RTS chatter (DOS console redirection toggles it per byte) then "HI",
// the data frame torn in half mid-payload.
client.Write(new byte[] { 0x01, 0x02, 0x00, 0x02, (byte)'H' }, 0, 5);
client.Flush();
Thread.Sleep(20);
client.Write(new byte[] { (byte)'I' }, 0, 1);
client.Flush();
WaitFor(() => device.BytesReceived == 2);
Assert.Equal(2, device.TextCharsDrawn);
}
[Fact]
public async Task Unknown_frame_type_drops_the_client_and_server_recovers()
{
string name = UniqueName();
var device = new VPlasmaDevice();
using var service = new VPlasmaPipeService(device, name);
service.Start();
using (var bad = Connect(name))
{
var hello = new byte[2];
bad.Read(hello, 0, 2);
bad.Write(new byte[] { 0x7F }, 0, 1); // not a frame type
bad.Flush();
// Contract: log + drop, no resync — our next read sees the close.
var eof = Task.Run(() =>
{
try { return bad.Read(new byte[1], 0, 1) == 0; }
catch (IOException) { return true; }
});
Assert.True(await Task.WhenAny(eof, Task.Delay(2000)) == eof,
"server did not drop the connection");
Assert.True(await eof);
}
using var good = Connect(name);
var again = new byte[2];
Assert.Equal(1, good.Read(again, 0, 1));
Assert.Equal(1, good.Read(again, 1, 1));
Assert.Equal(new byte[] { 0x01, 0x03 }, again);
}
}