using ClaudeDo.Data; using ClaudeDo.Data.Models; using ClaudeDo.Data.Repositories; using Microsoft.EntityFrameworkCore; using TaskStatus = ClaudeDo.Data.Models.TaskStatus; namespace ClaudeDo.Data.Tests; /// /// Verifies that TaskRepository.DeleteAsync and ListRepository.DeleteAsync /// delete the on-disk attachment directories for the affected tasks. /// public sealed class RepositoryAttachmentCleanupTests : IDisposable { private readonly string _dbPath; private readonly string _attachRoot; private readonly ClaudeDoDbContext _ctx; private readonly AttachmentStore _store; public RepositoryAttachmentCleanupTests() { _dbPath = Path.Combine(Path.GetTempPath(), $"claudedo_repoclean_{Guid.NewGuid():N}.db"); _attachRoot = Path.Combine(Path.GetTempPath(), $"claudedo_repoclean_att_{Guid.NewGuid():N}"); Directory.CreateDirectory(_attachRoot); var options = new DbContextOptionsBuilder() .UseSqlite($"Data Source={_dbPath}") .Options; _ctx = new ClaudeDoDbContext(options); _ctx.Database.EnsureCreated(); _store = new AttachmentStore(_attachRoot); } public void Dispose() { _ctx.Dispose(); foreach (var suffix in new[] { "", "-wal", "-shm" }) try { File.Delete(_dbPath + suffix); } catch { } try { Directory.Delete(_attachRoot, recursive: true); } catch { } } private async Task<(string listId, string taskId)> SeedAsync() { var listId = Guid.NewGuid().ToString(); var taskId = Guid.NewGuid().ToString(); _ctx.Lists.Add(new ListEntity { Id = listId, Name = "L", CreatedAt = DateTime.UtcNow }); _ctx.Tasks.Add(new TaskEntity { Id = taskId, ListId = listId, Title = "T", Status = TaskStatus.Idle, CreatedAt = DateTime.UtcNow, }); await _ctx.SaveChangesAsync(); return (listId, taskId); } [Fact] public async Task TaskRepository_DeleteAsync_RemovesAttachmentDir() { var (_, taskId) = await SeedAsync(); var taskDir = _store.TaskDir(taskId); Directory.CreateDirectory(taskDir); Assert.True(Directory.Exists(taskDir)); var repo = new TaskRepository(_ctx, _store); await repo.DeleteAsync(taskId); Assert.False(Directory.Exists(taskDir)); } [Fact] public async Task ListRepository_DeleteAsync_RemovesAttachmentDirForEachTask() { var (listId, taskId) = await SeedAsync(); var taskDir = _store.TaskDir(taskId); Directory.CreateDirectory(taskDir); Assert.True(Directory.Exists(taskDir)); var repo = new ListRepository(_ctx, _store); await repo.DeleteAsync(listId); Assert.False(Directory.Exists(taskDir)); } }