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(() => 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(() => 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 } }