PasteAsync silently swallowed every exception and returned void, so a package update renaming Iciclecreek's private write seam would break Ctrl+V/drop with zero user-visible signal. PasteAsync/SendTextAsync now return bool (mirroring SendLineAsync), and the view checks the result, routing a failure through InteractiveTerminalViewModel.ErrorReported -> ConPtyPaneViewModel.ErrorReported -> the existing footer error strip.
49 lines
1.6 KiB
C#
49 lines
1.6 KiB
C#
using System.Threading;
|
|
using ClaudeDo.Ui.Services;
|
|
using Xunit;
|
|
|
|
namespace ClaudeDo.Ui.Tests.Services;
|
|
|
|
public class PtyTerminalSessionTests
|
|
{
|
|
[Fact]
|
|
public async Task WaitForLaunchGateAsync_ThrowsTimeoutException_WhenGateStaysHeld()
|
|
{
|
|
using var gate = new SemaphoreSlim(0, 1); // never released — simulates a hung launch
|
|
|
|
await Assert.ThrowsAsync<TimeoutException>(() =>
|
|
PtyTerminalSession.WaitForLaunchGateAsync(gate, TimeSpan.FromMilliseconds(50), CancellationToken.None));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task WaitForLaunchGateAsync_DoesNotReleaseGate_ItNeverAcquired()
|
|
{
|
|
using var gate = new SemaphoreSlim(0, 1);
|
|
|
|
await Assert.ThrowsAsync<TimeoutException>(() =>
|
|
PtyTerminalSession.WaitForLaunchGateAsync(gate, TimeSpan.FromMilliseconds(50), CancellationToken.None));
|
|
|
|
Assert.Equal(0, gate.CurrentCount); // still held; a bad fix would Release() what it never acquired
|
|
}
|
|
|
|
[Fact]
|
|
public async Task WaitForLaunchGateAsync_AcquiresGate_WhenAvailable()
|
|
{
|
|
using var gate = new SemaphoreSlim(1, 1);
|
|
|
|
await PtyTerminalSession.WaitForLaunchGateAsync(gate, TimeSpan.FromSeconds(5), CancellationToken.None);
|
|
|
|
Assert.Equal(0, gate.CurrentCount); // acquired
|
|
}
|
|
|
|
// Fix: PasteAsync used to be void and swallow every failure. Not-started is the cheap case to
|
|
// cover without a real TerminalControl/ConPTY spawn.
|
|
[Fact]
|
|
public async Task PasteAsync_ReturnsFalse_WhenNotStarted()
|
|
{
|
|
using var session = new PtyTerminalSession();
|
|
|
|
Assert.False(await session.PasteAsync());
|
|
}
|
|
}
|