Merge claudedo/e5aeaf59fae840adaea3f1e912e203e1

This commit is contained in:
mika kuns
2026-08-10 14:58:35 +02:00
6 changed files with 174 additions and 30 deletions
@@ -769,7 +769,7 @@ public sealed class ExternalMcpServiceTests : IDisposable
var sut = BuildSut(CreateQueue());
await Assert.ThrowsAsync<InvalidOperationException>(
() => sut.GetTaskDiff(task.Id, false, CancellationToken.None));
() => sut.GetTaskDiff(task.Id, false, null, CancellationToken.None));
}
[Fact]
@@ -785,12 +785,52 @@ public sealed class ExternalMcpServiceTests : IDisposable
await mgr.CommitIfChangedAsync(wt, task, list, CancellationToken.None);
var sut = BuildSut(CreateQueue());
var diff = await sut.GetTaskDiff(task.Id, false, CancellationToken.None);
var diff = await sut.GetTaskDiff(task.Id, false, null, CancellationToken.None);
Assert.Contains("added.txt", diff.Files);
Assert.False(diff.Truncated);
}
[Fact]
public async Task GetTaskDiff_WithPathsFilter_ReturnsOnlyRequestedFile()
{
if (!GitAvailable) { Assert.True(true, "git not available -- skipping"); return; }
var (task, list, wt) = await SeedWorktreeAsync();
File.WriteAllText(Path.Combine(wt.WorktreePath, "added.txt"), "content");
File.WriteAllText(Path.Combine(wt.WorktreePath, "other.txt"), "other content");
var cfg = new WorkerConfig { WorktreeRootStrategy = "sibling" };
var mgr = new WorktreeManager(new GitService(), _db.CreateFactory(), cfg, NullLogger<WorktreeManager>.Instance);
await mgr.CommitIfChangedAsync(wt, task, list, CancellationToken.None);
var sut = BuildSut(CreateQueue());
var diff = await sut.GetTaskDiff(task.Id, false, ["added.txt"], CancellationToken.None);
Assert.Equal(new[] { "added.txt" }, diff.Files);
Assert.DoesNotContain("other.txt", diff.Content);
}
[Fact]
public async Task GetTaskDiff_StatMode_WithPathsFilter_ReturnsOnlyRequestedFile()
{
if (!GitAvailable) { Assert.True(true, "git not available -- skipping"); return; }
var (task, list, wt) = await SeedWorktreeAsync();
File.WriteAllText(Path.Combine(wt.WorktreePath, "added.txt"), "content");
File.WriteAllText(Path.Combine(wt.WorktreePath, "other.txt"), "other content");
var cfg = new WorkerConfig { WorktreeRootStrategy = "sibling" };
var mgr = new WorktreeManager(new GitService(), _db.CreateFactory(), cfg, NullLogger<WorktreeManager>.Instance);
await mgr.CommitIfChangedAsync(wt, task, list, CancellationToken.None);
var sut = BuildSut(CreateQueue());
var diff = await sut.GetTaskDiff(task.Id, true, ["other.txt"], CancellationToken.None);
Assert.Equal(new[] { "other.txt" }, diff.Files);
Assert.DoesNotContain("added.txt", diff.Content);
}
[Fact]
public async Task GetTaskDiff_WorktreeLessHandlerTask_UsesHandlerCommitRangeOverListWorkingDir()
{
@@ -819,7 +859,7 @@ public sealed class ExternalMcpServiceTests : IDisposable
}
var sut = BuildSut(CreateQueue());
var diff = await sut.GetTaskDiff(task.Id, false, CancellationToken.None);
var diff = await sut.GetTaskDiff(task.Id, false, null, CancellationToken.None);
Assert.Contains("handled.txt", diff.Files);
Assert.False(diff.Truncated);
@@ -850,7 +890,7 @@ public sealed class ExternalMcpServiceTests : IDisposable
}
var sut = BuildSut(CreateQueue());
var diff = await sut.GetTaskDiff(task.Id, true, CancellationToken.None);
var diff = await sut.GetTaskDiff(task.Id, true, null, CancellationToken.None);
Assert.Contains("handled.txt", diff.Content);
}
@@ -1637,6 +1677,52 @@ public sealed class ExternalMcpServiceTests : IDisposable
Assert.Equal(
new[] { taskA.Id, taskB.Id }.OrderBy(x => x),
overlap.TaskIds.OrderBy(x => x));
// Equal file sets overlap but neither is a PROPER subset of the other.
Assert.Empty(result.Subsets);
}
[Fact]
public async Task PreviewMergeSet_TaskFilesAreProperSubsetOfAnother_ReportsSubset()
{
if (!GitAvailable) { Assert.True(true, "git not available -- skipping"); return; }
var repo = new GitRepoFixture();
_repos.Add(repo);
GitRepoFixture.RunGit(repo.RepoDir, "branch", "-m", "main");
var listId = Guid.NewGuid().ToString();
await _lists.AddAsync(new ListEntity { Id = listId, Name = "L", WorkingDir = repo.RepoDir, CreatedAt = DateTime.UtcNow });
var subsetTask = await SeedTaskAsync(listId, "subset", TaskStatus.WaitingForReview);
var supersetTask = await SeedTaskAsync(listId, "superset", TaskStatus.WaitingForReview);
await CreateActiveWorktreeAsync(repo, subsetTask.Id, "shared.txt", "shared change\n");
var wtPath = Path.Combine(Path.GetTempPath(), $"wt_{Guid.NewGuid():N}");
_worktreeCleanups.Add((repo.RepoDir, wtPath));
var branch = $"claudedo/{supersetTask.Id[..8]}";
GitRepoFixture.RunGit(repo.RepoDir, "worktree", "add", "-b", branch, wtPath, repo.BaseCommit);
File.WriteAllText(Path.Combine(wtPath, "shared.txt"), "shared change too\n");
File.WriteAllText(Path.Combine(wtPath, "extra.txt"), "extra\n");
GitRepoFixture.RunGit(wtPath, "add", "-A");
GitRepoFixture.RunGit(wtPath, "commit", "-m", "edit shared+extra");
using (var ctx = _db.CreateContext())
{
ctx.Worktrees.Add(new WorktreeEntity
{
TaskId = supersetTask.Id, Path = wtPath, BranchName = branch,
BaseCommit = repo.BaseCommit,
HeadCommit = GitRepoFixture.RunGit(wtPath, "rev-parse", "HEAD").Trim(),
State = WorktreeState.Active, CreatedAt = DateTime.UtcNow,
});
await ctx.SaveChangesAsync();
}
var sut = BuildSut(CreateQueue());
var result = await sut.PreviewMergeSet([subsetTask.Id, supersetTask.Id], "main", CancellationToken.None);
var relation = Assert.Single(result.Subsets);
Assert.Equal(subsetTask.Id, relation.TaskId);
Assert.Equal(supersetTask.Id, relation.SupersetTaskId);
}
[Fact]