using ClaudeDo.Worker.Findings; using ClaudeDo.Worker.Tests.Infrastructure; namespace ClaudeDo.Worker.Tests.Findings; public sealed class FindingsStoreGitTests : IDisposable { private readonly GitRepoFixture _repo = new(); public void Dispose() => _repo.Dispose(); private static FindingInput Input(string slug) => new(slug, "Something is not what it looks like", "Body.", "src", "task-1", "abc1234"); [Fact] public async Task SaveAsync_WhenNotTracked_ExcludesStoreFromGitOnce() { if (!GitRepoFixture.IsGitAvailable()) return; var store = new FindingsStore(); await store.SaveAsync(_repo.RepoDir, Input("first"), CancellationToken.None, tracked: false); await store.SaveAsync(_repo.RepoDir, Input("second"), CancellationToken.None, tracked: false); var exclude = await File.ReadAllLinesAsync(Path.Combine(_repo.RepoDir, ".git", "info", "exclude")); Assert.Single(exclude, l => l.Trim() == "/.claudedo/"); } [Fact] public async Task SaveAsync_WhenTracked_DoesNotTouchExclude() { if (!GitRepoFixture.IsGitAvailable()) return; var store = new FindingsStore(); await store.SaveAsync(_repo.RepoDir, Input("first"), CancellationToken.None, tracked: true); var excludePath = Path.Combine(_repo.RepoDir, ".git", "info", "exclude"); var lines = File.Exists(excludePath) ? await File.ReadAllLinesAsync(excludePath) : Array.Empty(); Assert.DoesNotContain(lines, l => l.Trim() == "/.claudedo/"); } }