refactor(claude-do): merge TaskRowViewModel: CanX und DisabledReason aus einer Gate-Met
ClaudeDo-Task: 6c4b27aa-1b5e-4d73-98f5-dcafa3935247
This commit is contained in:
@@ -159,4 +159,76 @@ public class TaskRowContextMenuTests
|
||||
row.IsSelected = isSelected;
|
||||
Assert.Equal(expected, row.ShowRowActions);
|
||||
}
|
||||
|
||||
// Pins down what the gate methods guarantee by construction: each of the five CanX/reason
|
||||
// pairs must agree on every reachable state, not just the handful of examples above. Swept
|
||||
// across the full state matrix (every TaskStatus x PlanningPhase x IsChild/ParentFinalized x
|
||||
// IsManual x HasInteractiveSession x HasQueuedSubtasks x IsRefining) rather than one example
|
||||
// per gate, so a future edit to a gate's condition without touching its Reason branch (or
|
||||
// vice versa) fails loudly instead of silently drifting.
|
||||
public static IEnumerable<object[]> GateStateMatrix()
|
||||
{
|
||||
foreach (var status in Enum.GetValues<TaskStatus>())
|
||||
foreach (var phase in Enum.GetValues<PlanningPhase>())
|
||||
foreach (var isChild in Bools)
|
||||
foreach (var parentFinalized in Bools)
|
||||
foreach (var isManual in Bools)
|
||||
foreach (var hasInteractiveSession in Bools)
|
||||
foreach (var hasQueuedSubtasks in Bools)
|
||||
foreach (var isRefining in Bools)
|
||||
yield return new object[]
|
||||
{
|
||||
status, phase, isChild, parentFinalized, isManual,
|
||||
hasInteractiveSession, hasQueuedSubtasks, isRefining,
|
||||
};
|
||||
}
|
||||
|
||||
private static readonly bool[] Bools = { false, true };
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GateStateMatrix))]
|
||||
public void CanX_Agrees_With_DisabledReason_Across_State_Matrix(
|
||||
TaskStatus status, PlanningPhase phase, bool isChild, bool parentFinalized, bool isManual,
|
||||
bool hasInteractiveSession, bool hasQueuedSubtasks, bool isRefining)
|
||||
{
|
||||
var row = new TaskRowViewModel
|
||||
{
|
||||
Id = "t1",
|
||||
Status = status,
|
||||
PlanningPhase = phase,
|
||||
ParentTaskId = isChild ? "parent-id" : null,
|
||||
ParentFinalized = parentFinalized,
|
||||
IsManual = isManual,
|
||||
HasInteractiveSession = hasInteractiveSession,
|
||||
HasQueuedSubtasks = hasQueuedSubtasks,
|
||||
IsRefining = isRefining,
|
||||
};
|
||||
|
||||
Assert.Equal(row.CanSendToQueue, row.SendToQueueDisabledReason is null);
|
||||
Assert.Equal(row.IsRunning, row.CancelDisabledReason is null);
|
||||
Assert.Equal(row.CanRefine, row.RefineDisabledReason is null);
|
||||
|
||||
var canOpenPlanningMenu = row.CanOpenPlanningSession || row.CanResumeOrDiscardPlanning || row.CanFinalizePlanning;
|
||||
Assert.Equal(canOpenPlanningMenu, row.PlanningDisabledReason is null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenWorktreeDisabledReason_Agrees_With_CanOpenWorktree_When_NoPath()
|
||||
{
|
||||
var row = MakeRow();
|
||||
Assert.Equal(row.CanOpenWorktree, row.OpenWorktreeDisabledReason is null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenWorktreeDisabledReason_Agrees_With_CanOpenWorktree_When_Path_Exists()
|
||||
{
|
||||
var dir = Directory.CreateTempSubdirectory();
|
||||
try
|
||||
{
|
||||
var row = MakeRow();
|
||||
row.WorktreePath = dir.FullName;
|
||||
Assert.Equal(row.CanOpenWorktree, row.OpenWorktreeDisabledReason is null);
|
||||
}
|
||||
finally { dir.Delete(true); }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user