using ClaudeDo.Worker.Runner; using ClaudeDo.Worker.Runner.Interfaces; namespace ClaudeDo.Worker.Tests.Runner; public sealed class LiveSessionRegistryTests { private sealed class FakeLiveSession : ILiveSession { public bool StopCalled { get; private set; } public bool IsTurnInFlight => false; public Task SendUserMessageAsync(string text, CancellationToken ct) => Task.CompletedTask; public Task RemoveQueuedAsync(string text, CancellationToken ct) => Task.CompletedTask; public Task InterruptAsync(CancellationToken ct) => Task.CompletedTask; public Task StopAsync() { StopCalled = true; return Task.CompletedTask; } public ValueTask DisposeAsync() => ValueTask.CompletedTask; } [Fact] public void Register_ThenTryGet_ReturnsSession() { var registry = new LiveSessionRegistry(); var session = new FakeLiveSession(); registry.Register("task-1", session); Assert.True(registry.TryGet("task-1", out var retrieved)); Assert.Same(session, retrieved); } [Fact] public void TryGet_Missing_ReturnsFalse() { var registry = new LiveSessionRegistry(); Assert.False(registry.TryGet("no-such-task", out _)); } [Fact] public void Unregister_RemovesSession() { var registry = new LiveSessionRegistry(); registry.Register("task-1", new FakeLiveSession()); registry.Unregister("task-1"); Assert.False(registry.TryGet("task-1", out _)); } [Fact] public async Task Register_WhenSessionAlreadyExists_StopsPreviousSession() { var registry = new LiveSessionRegistry(); var first = new FakeLiveSession(); var second = new FakeLiveSession(); registry.Register("task-1", first); registry.Register("task-1", second); // Give the fire-and-forget stop a tick to run. await Task.Delay(50); Assert.True(first.StopCalled); Assert.True(registry.TryGet("task-1", out var retrieved)); Assert.Same(second, retrieved); } [Fact] public async Task StopAsync_StopsAndRemovesSession() { var registry = new LiveSessionRegistry(); var session = new FakeLiveSession(); registry.Register("task-1", session); await registry.StopAsync("task-1"); Assert.True(session.StopCalled); Assert.False(registry.TryGet("task-1", out _)); } [Fact] public async Task StopAsync_MissingTask_DoesNotThrow() { var registry = new LiveSessionRegistry(); await registry.StopAsync("no-such-task"); // should not throw } }