using ClaudeDo.Data; using ClaudeDo.Data.Models; using ClaudeDo.Data.Repositories; using ClaudeDo.Worker.External; using ClaudeDo.Worker.Hub; using ClaudeDo.Worker.Tests.Infrastructure; using Microsoft.AspNetCore.SignalR; namespace ClaudeDo.Worker.Tests.External; internal sealed class ListToolsHubClients : IHubClients { public ListToolsClientProxy Proxy { get; } = new(); public IClientProxy All => Proxy; public IClientProxy AllExcept(IReadOnlyList e) => Proxy; public IClientProxy Client(string c) => Proxy; public IClientProxy Clients(IReadOnlyList c) => Proxy; public IClientProxy Group(string g) => Proxy; public IClientProxy GroupExcept(string g, IReadOnlyList e) => Proxy; public IClientProxy Groups(IReadOnlyList g) => Proxy; public IClientProxy User(string u) => Proxy; public IClientProxy Users(IReadOnlyList u) => Proxy; } internal sealed class ListToolsClientProxy : IClientProxy { public Task SendCoreAsync(string m, object?[] a, CancellationToken ct = default) => Task.CompletedTask; } internal sealed class ListToolsHubContext : IHubContext { public ListToolsHubClients RecordingClients { get; } = new(); public IHubClients Clients => RecordingClients; public IGroupManager Groups => throw new NotImplementedException(); } public sealed class ListMcpToolsTests : IDisposable { private readonly DbFixture _db = new(); private readonly ClaudeDoDbContext _ctx; private readonly ListRepository _lists; private readonly ListMcpTools _sut; public ListMcpToolsTests() { _ctx = _db.CreateContext(); _lists = new ListRepository(_ctx); _sut = new ListMcpTools(_lists, new HubBroadcaster(new ListToolsHubContext())); } public void Dispose() { _ctx.Dispose(); _db.Dispose(); } [Fact] public async Task CreateList_PersistsWithDefaults() { var dto = await _sut.CreateList("My List", null, null, CancellationToken.None); Assert.Equal("My List", dto.Name); var loaded = await _lists.GetByIdAsync(dto.Id); Assert.NotNull(loaded); Assert.Equal("chore", loaded!.DefaultCommitType); } [Fact] public async Task UpdateList_PatchesNameWorkingDirAndCommitType() { var created = await _sut.CreateList("orig", null, null, CancellationToken.None); var dto = await _sut.UpdateList(created.Id, "renamed", "C:/work", "feat", CancellationToken.None); Assert.Equal("renamed", dto.Name); Assert.Equal("C:/work", dto.WorkingDir); var loaded = await _lists.GetByIdAsync(created.Id); Assert.Equal("feat", loaded!.DefaultCommitType); } [Fact] public async Task UpdateList_NotFound_Throws() { await Assert.ThrowsAsync(() => _sut.UpdateList("missing", "x", null, null, CancellationToken.None)); } [Fact] public async Task DeleteList_RemovesList() { var created = await _sut.CreateList("gone", null, null, CancellationToken.None); await _sut.DeleteList(created.Id, CancellationToken.None); Assert.Null(await _lists.GetByIdAsync(created.Id)); } }