diff --git a/tests/ClaudeDo.Ui.Tests/ViewModels/TaskMonitorViewModelTests.cs b/tests/ClaudeDo.Ui.Tests/ViewModels/TaskMonitorViewModelTests.cs new file mode 100644 index 0000000..d9f9f02 --- /dev/null +++ b/tests/ClaudeDo.Ui.Tests/ViewModels/TaskMonitorViewModelTests.cs @@ -0,0 +1,102 @@ +using ClaudeDo.Data; +using ClaudeDo.Ui.ViewModels.Islands; +using Microsoft.EntityFrameworkCore; +using Xunit; + +namespace ClaudeDo.Ui.Tests.ViewModels; + +public class TaskMonitorViewModelTests : IDisposable +{ + private readonly string _dbPath; + + public TaskMonitorViewModelTests() + { + _dbPath = Path.Combine(Path.GetTempPath(), $"claudedo_monitor_{Guid.NewGuid():N}.db"); + using var ctx = NewContext(); + ctx.Database.EnsureCreated(); + } + + public void Dispose() + { + try { File.Delete(_dbPath); } catch { } + try { File.Delete(_dbPath + "-wal"); } catch { } + try { File.Delete(_dbPath + "-shm"); } catch { } + } + + private ClaudeDoDbContext NewContext() + { + var opts = new DbContextOptionsBuilder() + .UseSqlite($"Data Source={_dbPath}") + .Options; + return new ClaudeDoDbContext(opts); + } + + private sealed class TestDbFactory : IDbContextFactory + { + private readonly Func _create; + public TestDbFactory(Func create) => _create = create; + public ClaudeDoDbContext CreateDbContext() => _create(); + } + + private sealed class FakeWorker : StubWorkerClient { } + + private TaskMonitorViewModel Build(FakeWorker worker) + => new TaskMonitorViewModel(new TestDbFactory(NewContext), worker); + + [Fact] + public void Feeds_AccumulateLogLines_WithKinds() + { + var worker = new FakeWorker(); + using var vm = Build(worker); + vm.SetTaskId("t1"); + + worker.RaiseTaskMessage("t1", "[sys] boot"); + worker.RaiseTaskMessage("t1", "[tool] read file"); + worker.RaiseTaskMessage("t1", "[claude] hello"); + + Assert.Equal(3, vm.Log.Count); + Assert.Equal(LogKind.Sys, vm.Log[0].Kind); + Assert.Equal(LogKind.Tool, vm.Log[1].Kind); + Assert.Equal(LogKind.Claude, vm.Log[2].Kind); + } + + [Fact] + public void Feeds_ForOtherTask_AreIgnored() + { + var worker = new FakeWorker(); + using var vm = Build(worker); + vm.SetTaskId("t1"); + + worker.RaiseTaskMessage("other", "[sys] not mine"); + + Assert.Empty(vm.Log); + } + + [Fact] + public void TaskFinished_FlipsState_AndAppendsDoneLine() + { + var worker = new FakeWorker(); + using var vm = Build(worker); + vm.SetTaskId("t1"); + + worker.RaiseTaskFinished("slot-1", "t1", "done", DateTime.UtcNow); + + Assert.True(vm.IsDone); + Assert.Equal("done", vm.AgentState); + Assert.Equal(LogKind.Done, vm.Log[^1].Kind); + } + + [Fact] + public void ApplyOutcome_SplitsRoadblockMarker() + { + var worker = new FakeWorker(); + using var vm = Build(worker); + + vm.ApplyOutcome( + "Summary text\n\nRoadblocks reported during the run:\n- something broke", + errorFallback: null); + + Assert.Equal("Summary text", vm.SessionOutcome); + Assert.Equal("- something broke", vm.Roadblocks); + } +}