using ClaudeDo.Data.Git; using ClaudeDo.Worker.Tests.Infrastructure; namespace ClaudeDo.Worker.Tests.Runner; public class GitServicePreviewMergeTests : IDisposable { private readonly List _repos = new(); private GitRepoFixture NewRepo() { var r = new GitRepoFixture(); _repos.Add(r); return r; } public void Dispose() { foreach (var r in _repos) try { r.Dispose(); } catch { } } [Fact] public async Task PreviewMergeAsync_NonConflicting_ReportsCleanWithChangedCount() { if (!GitRepoFixture.IsGitAvailable()) return; var repo = NewRepo(); var git = new GitService(); var baseBranch = await git.GetCurrentBranchAsync(repo.RepoDir); GitRepoFixture.RunGit(repo.RepoDir, "checkout", "-b", "feature"); File.WriteAllText(Path.Combine(repo.RepoDir, "newfile.txt"), "x\n"); GitRepoFixture.RunGit(repo.RepoDir, "add", "-A"); GitRepoFixture.RunGit(repo.RepoDir, "commit", "-m", "feat"); GitRepoFixture.RunGit(repo.RepoDir, "checkout", baseBranch); var preview = await git.PreviewMergeAsync(repo.RepoDir, baseBranch, "feature", CancellationToken.None); Assert.True(preview.Supported); Assert.True(preview.Clean); Assert.Empty(preview.ConflictFiles); var count = await git.CountChangedFilesAsync(repo.RepoDir, baseBranch, "feature", CancellationToken.None); Assert.Equal(1, count); } [Fact] public async Task PreviewMergeAsync_Conflicting_ReportsFilesAndDoesNotMutateTree() { if (!GitRepoFixture.IsGitAvailable()) return; var repo = NewRepo(); var git = new GitService(); var baseBranch = await git.GetCurrentBranchAsync(repo.RepoDir); GitRepoFixture.RunGit(repo.RepoDir, "checkout", "-b", "feature"); File.WriteAllText(Path.Combine(repo.RepoDir, "README.md"), "# from feature\n"); GitRepoFixture.RunGit(repo.RepoDir, "add", "-A"); GitRepoFixture.RunGit(repo.RepoDir, "commit", "-m", "feat readme"); GitRepoFixture.RunGit(repo.RepoDir, "checkout", baseBranch); File.WriteAllText(Path.Combine(repo.RepoDir, "README.md"), "# from base\n"); GitRepoFixture.RunGit(repo.RepoDir, "add", "-A"); GitRepoFixture.RunGit(repo.RepoDir, "commit", "-m", "base readme"); var headBefore = GitRepoFixture.RunGit(repo.RepoDir, "rev-parse", "HEAD").Trim(); var preview = await git.PreviewMergeAsync(repo.RepoDir, baseBranch, "feature", CancellationToken.None); Assert.True(preview.Supported); Assert.False(preview.Clean); Assert.Contains("README.md", preview.ConflictFiles); Assert.Equal(headBefore, GitRepoFixture.RunGit(repo.RepoDir, "rev-parse", "HEAD").Trim()); Assert.False(await git.IsMidMergeAsync(repo.RepoDir)); } }