using ClaudeDo.Data; using ClaudeDo.Data.Repositories; using ClaudeDo.Worker.External; using ClaudeDo.Worker.Hub; using ClaudeDo.Worker.Tests.Infrastructure; namespace ClaudeDo.Worker.Tests.External; public sealed class NotesMcpToolsTests : IDisposable { private readonly DbFixture _db = new(); private readonly ClaudeDoDbContext _ctx; private readonly DailyNoteRepository _notes; private readonly NotesMcpTools _sut; private static readonly DateOnly Today = DateOnly.FromDateTime(DateTime.Today); public NotesMcpToolsTests() { _ctx = _db.CreateContext(); _notes = new DailyNoteRepository(_ctx); _sut = new NotesMcpTools(_notes, new HubBroadcaster(new CapturingHubContext())); } public void Dispose() { _ctx.Dispose(); _db.Dispose(); } [Fact] public async Task AddNote_stores_it_on_today_flagged_as_agent_written() { var result = await _sut.AddNote(" Mika decided to keep the daily grouping. "); Assert.True(result.Saved); var row = Assert.Single(await _notes.ListByDayAsync(Today)); Assert.Equal("Mika decided to keep the daily grouping.", row.Text); Assert.True(row.FromAgent); Assert.Equal(NotesMcpTools.DailyAgentCap - 1, result.RemainingToday); } [Fact] public async Task AddNote_refuses_once_the_daily_cap_is_used_up_and_saves_nothing() { for (var i = 0; i < NotesMcpTools.DailyAgentCap; i++) await _sut.AddNote($"note {i}"); var ex = await Assert.ThrowsAsync(() => _sut.AddNote("one too many")); Assert.Contains("cap", ex.Message, StringComparison.OrdinalIgnoreCase); Assert.Equal(NotesMcpTools.DailyAgentCap, (await _notes.ListByDayAsync(Today)).Count); } [Fact] public async Task Notes_the_user_wrote_do_not_count_against_the_agent_cap() { for (var i = 0; i < NotesMcpTools.DailyAgentCap; i++) await _notes.AddAsync(Today, $"mine {i}"); var result = await _sut.AddNote("still allowed"); Assert.Equal(1, result.AgentNotesToday); } [Theory] [InlineData("")] [InlineData(" ")] public async Task AddNote_rejects_empty_text(string text) => await Assert.ThrowsAsync(() => _sut.AddNote(text)); [Fact] public async Task AddNote_rejects_text_past_the_length_limit() { var tooLong = new string('x', NotesMcpTools.MaxLength + 1); var ex = await Assert.ThrowsAsync(() => _sut.AddNote(tooLong)); Assert.Contains(NotesMcpTools.MaxLength.ToString(), ex.Message); Assert.Empty(await _notes.ListByDayAsync(Today)); } }