168 lines
5.8 KiB
C#
168 lines
5.8 KiB
C#
using ClaudeDo.Data.Models;
|
|
using ClaudeDo.Ui.Services;
|
|
using ClaudeDo.Ui.ViewModels.Modals;
|
|
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
|
|
using Xunit;
|
|
|
|
namespace ClaudeDo.Ui.Tests.ViewModels;
|
|
|
|
public class WorktreesOverviewBatchMergeTests
|
|
{
|
|
private static WorktreeOverviewRowViewModel ActiveRow(string id) => new()
|
|
{
|
|
TaskId = id,
|
|
TaskTitle = $"Task {id}",
|
|
TaskStatus = TaskStatus.WaitingForReview,
|
|
State = WorktreeState.Active,
|
|
};
|
|
|
|
[Fact]
|
|
public void Row_outcome_helpers_reflect_state()
|
|
{
|
|
var row = ActiveRow("a");
|
|
Assert.Equal(BatchMergeOutcome.None, row.MergeOutcome);
|
|
Assert.False(row.IsConflict);
|
|
|
|
row.MergeOutcome = BatchMergeOutcome.Conflict;
|
|
Assert.True(row.IsConflict);
|
|
|
|
row.MergeOutcome = BatchMergeOutcome.Merged;
|
|
Assert.False(row.IsConflict);
|
|
}
|
|
|
|
private static WorktreesOverviewModalViewModel NewVm() =>
|
|
new(new ClaudeDo.Ui.Services.WorkerClient("http://127.0.0.1:1/hub"), () => null!);
|
|
|
|
private static MergeResultDto Merged() => new("merged", System.Array.Empty<string>(), null);
|
|
private static MergeResultDto Conflict() => new("conflict", new[] { "f.cs" }, null);
|
|
private static MergeResultDto Blocked() => new("blocked", System.Array.Empty<string>(), "blocked");
|
|
|
|
[Fact]
|
|
public async System.Threading.Tasks.Task MergeSelected_only_processes_checked_active_rows()
|
|
{
|
|
var vm = NewVm();
|
|
var a = ActiveRow("a"); a.IsChecked = true;
|
|
var b = ActiveRow("b"); b.IsChecked = false;
|
|
var c = ActiveRow("c"); c.IsChecked = true; c.State = WorktreeState.Merged;
|
|
vm.Rows.Add(a); vm.Rows.Add(b); vm.Rows.Add(c);
|
|
vm.SelectedTarget = "main";
|
|
|
|
var seen = new System.Collections.Generic.List<string>();
|
|
await vm.MergeSelectedAsync((id, target, remove, msg) =>
|
|
{
|
|
seen.Add(id);
|
|
Assert.Equal("main", target);
|
|
Assert.False(remove);
|
|
return System.Threading.Tasks.Task.FromResult(Merged());
|
|
});
|
|
|
|
Assert.Equal(new[] { "a" }, seen);
|
|
Assert.Equal(BatchMergeOutcome.Merged, a.MergeOutcome);
|
|
Assert.False(a.IsChecked);
|
|
}
|
|
|
|
[Fact]
|
|
public async System.Threading.Tasks.Task MergeSelected_continues_past_conflict_and_collects_it()
|
|
{
|
|
var vm = NewVm();
|
|
var a = ActiveRow("a"); a.IsChecked = true;
|
|
var b = ActiveRow("b"); b.IsChecked = true;
|
|
var c = ActiveRow("c"); c.IsChecked = true;
|
|
vm.Rows.Add(a); vm.Rows.Add(b); vm.Rows.Add(c);
|
|
vm.SelectedTarget = "main";
|
|
|
|
await vm.MergeSelectedAsync((id, target, remove, msg) =>
|
|
System.Threading.Tasks.Task.FromResult(id == "b" ? Conflict() : Merged()));
|
|
|
|
Assert.Equal(BatchMergeOutcome.Merged, a.MergeOutcome);
|
|
Assert.Equal(BatchMergeOutcome.Conflict, b.MergeOutcome);
|
|
Assert.Equal(BatchMergeOutcome.Merged, c.MergeOutcome);
|
|
Assert.Contains(b, vm.ConflictRows);
|
|
Assert.Single(vm.ConflictRows);
|
|
}
|
|
|
|
[Fact]
|
|
public async System.Threading.Tasks.Task MergeSelected_maps_blocked_and_exception_to_failure_outcomes()
|
|
{
|
|
var vm = NewVm();
|
|
var a = ActiveRow("a"); a.IsChecked = true;
|
|
var b = ActiveRow("b"); b.IsChecked = true;
|
|
vm.Rows.Add(a); vm.Rows.Add(b);
|
|
vm.SelectedTarget = "main";
|
|
|
|
await vm.MergeSelectedAsync((id, target, remove, msg) => id == "a"
|
|
? System.Threading.Tasks.Task.FromResult(Blocked())
|
|
: throw new System.InvalidOperationException("boom"));
|
|
|
|
Assert.Equal(BatchMergeOutcome.Blocked, a.MergeOutcome);
|
|
Assert.Equal(BatchMergeOutcome.Failed, b.MergeOutcome);
|
|
Assert.Empty(vm.ConflictRows);
|
|
Assert.False(vm.IsMerging);
|
|
}
|
|
|
|
[Fact]
|
|
public async System.Threading.Tasks.Task MergeSelected_noop_when_no_target()
|
|
{
|
|
var vm = NewVm();
|
|
var a = ActiveRow("a"); a.IsChecked = true;
|
|
vm.Rows.Add(a);
|
|
vm.SelectedTarget = null;
|
|
|
|
var called = false;
|
|
await vm.MergeSelectedAsync((id, t, r, m) => { called = true; return System.Threading.Tasks.Task.FromResult(Merged()); });
|
|
|
|
Assert.False(called);
|
|
Assert.Equal(BatchMergeOutcome.None, a.MergeOutcome);
|
|
}
|
|
|
|
[Fact]
|
|
public void SelectedCount_tracks_checked_active_rows()
|
|
{
|
|
var vm = NewVm();
|
|
var a = ActiveRow("a");
|
|
var b = ActiveRow("b");
|
|
var merged = ActiveRow("c"); merged.State = WorktreeState.Merged;
|
|
vm.AddRowForTest(a); vm.AddRowForTest(b); vm.AddRowForTest(merged);
|
|
|
|
Assert.Equal(0, vm.SelectedCount);
|
|
a.IsChecked = true;
|
|
Assert.Equal(1, vm.SelectedCount);
|
|
b.IsChecked = true;
|
|
merged.IsChecked = true;
|
|
Assert.Equal(2, vm.SelectedCount);
|
|
a.IsChecked = false;
|
|
Assert.Equal(1, vm.SelectedCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolveConflict_invokes_seam_with_task_and_target()
|
|
{
|
|
var vm = NewVm();
|
|
vm.SelectedTarget = "release";
|
|
var row = ActiveRow("x"); row.MergeOutcome = BatchMergeOutcome.Conflict;
|
|
|
|
(string Task, string Target)? captured = null;
|
|
vm.RequestConflictResolution = (taskId, target) => { captured = (taskId, target); return System.Threading.Tasks.Task.CompletedTask; };
|
|
|
|
vm.ResolveConflictCommand.Execute(row);
|
|
|
|
Assert.Equal(("x", "release"), captured);
|
|
}
|
|
|
|
[Fact]
|
|
public void MergeAll_canExecute_requires_target_selection_and_idle()
|
|
{
|
|
var vm = NewVm();
|
|
var a = ActiveRow("a");
|
|
vm.AddRowForTest(a);
|
|
|
|
Assert.False(vm.MergeAllCommand.CanExecute(null));
|
|
a.IsChecked = true;
|
|
Assert.False(vm.MergeAllCommand.CanExecute(null));
|
|
vm.SelectedTarget = "main";
|
|
Assert.True(vm.MergeAllCommand.CanExecute(null));
|
|
vm.IsMerging = true;
|
|
Assert.False(vm.MergeAllCommand.CanExecute(null));
|
|
}
|
|
}
|