Files
nexus/backend-tests/TaskBoardTests.cs
devops ac131f7f53 feat: Parent-Child TaskFlow — Delegated durch sichtbare Child-Tasks ersetzt
- Delegated State aus Board, Entities, DTOs, Frontend-Spalten und Tests entfernt
- Parent-Tasks bleiben InProgress waehrend delegierter Agentenarbeit
- Child-Tasks laufen sichtbar mit normalen States und parentTaskId
- Doku: README, Phase 3, Changelog, Controller-Kommentare angepasst
- openclaw-task-board-flow.md als Referenzdoku hinzugefuegt
- 73/73 Backend-Tests gruen, Frontend-Build gruen
2026-06-21 21:30:52 +02:00

246 lines
8.0 KiB
C#

using Nexus.Api.Data;
using Xunit;
namespace Nexus.Api.Tests;
public class TaskBoardTests
{
// ── TaskStateHelper: BoardGroupKey ──
[Theory]
[InlineData("Backlog", "offen")]
[InlineData("In progress", "inProgress")]
[InlineData("Review", "review")]
[InlineData("Blocked", "blocked")]
[InlineData("Done", "done")]
[InlineData("backlog", "offen")]
[InlineData("in progress", "inProgress")]
[InlineData("review", "review")]
[InlineData("blocked", "blocked")]
[InlineData("done", "done")]
[InlineData("", "offen")]
[InlineData(null, "offen")]
[InlineData("unknown", "offen")]
public void BoardGroupKey_ReturnsExpectedGroup(string? state, string expected)
{
var result = TaskStateHelper.BoardGroupKey(state);
Assert.Equal(expected, result);
}
// ── TaskStateHelper: BoardGroupToState ──
[Theory]
[InlineData("offen", "Backlog")]
[InlineData("inProgress", "In progress")]
[InlineData("inprogress", "In progress")]
[InlineData("review", "Review")]
[InlineData("blocked", "Blocked")]
[InlineData("done", "Done")]
[InlineData("Offen", "Backlog")]
[InlineData("", null)]
[InlineData(null, null)]
[InlineData("unknown", null)]
public void BoardGroupToState_ReturnsExpectedState(string? groupKey, string? expected)
{
var result = TaskStateHelper.BoardGroupToState(groupKey);
Assert.Equal(expected, result);
}
// ── TaskStateHelper: AllStates has 5 entries ──
[Fact]
public void AllStates_ContainsAllFiveStates()
{
var states = TaskStateHelper.AllStates;
Assert.Equal(5, states.Length);
Assert.Contains("Backlog", states);
Assert.Contains("In progress", states);
Assert.Contains("Review", states);
Assert.Contains("Blocked", states);
Assert.Contains("Done", states);
}
// ── TaskStateHelper: IsValidState ──
[Theory]
[InlineData("Backlog", true)]
[InlineData("In progress", true)]
[InlineData("Review", true)]
[InlineData("Blocked", true)]
[InlineData("Done", true)]
[InlineData("backlog", true)]
[InlineData("offen", false)]
[InlineData("", false)]
[InlineData(null, false)]
[InlineData("unknown", false)]
public void IsValidState_ReturnsCorrectResult(string? state, bool expected)
{
Assert.Equal(expected, TaskStateHelper.IsValidState(state));
}
// ── TaskStateHelper: IsInProgressOrBlocked ──
[Theory]
[InlineData("In progress", true)]
[InlineData("Blocked", true)]
[InlineData("Backlog", false)]
[InlineData("Review", false)]
[InlineData("Done", false)]
[InlineData(null, false)]
public void IsInProgressOrBlocked_ReturnsCorrectResult(string? state, bool expected)
{
Assert.Equal(expected, TaskStateHelper.IsInProgressOrBlocked(state));
}
// ── TaskStateHelper: IsDoneOrBacklog ──
[Theory]
[InlineData("Done", true)]
[InlineData("Backlog", true)]
[InlineData("In progress", false)]
[InlineData("Review", false)]
[InlineData("Blocked", false)]
[InlineData(null, false)]
public void IsDoneOrBacklog_ReturnsCorrectResult(string? state, bool expected)
{
Assert.Equal(expected, TaskStateHelper.IsDoneOrBacklog(state));
}
// ── TaskStateHelper: ToDisplayString ──
[Theory]
[InlineData("Backlog", "Offen")]
[InlineData("In progress", "In Bearbeitung")]
[InlineData("Review", "Review")]
[InlineData("Blocked", "Blockiert")]
[InlineData("Done", "Erledigt")]
[InlineData("backlog", "Offen")]
[InlineData("", "")]
[InlineData(null, "")]
[InlineData("unknown", "unknown")]
public void ToDisplayString_ReturnsGermanLabel(string? state, string expected)
{
Assert.Equal(expected, TaskStateHelper.ToDisplayString(state));
}
// ── TaskState helper: ToStateString and ToTaskState roundtrip ──
[Fact]
public void ToStateString_And_ToTaskState_RoundTrip()
{
var states = new[] { TaskState.Backlog, TaskState.InProgress, TaskState.Review, TaskState.Blocked, TaskState.Done };
foreach (var state in states)
{
var str = state.ToStateString();
var parsed = str.ToTaskState();
Assert.Equal(state, parsed);
}
}
[Fact]
public void ToTaskState_DefaultsToBacklog_ForUnknownString()
{
Assert.Equal(TaskState.Backlog, "unknown".ToTaskState());
}
// ── TaskStateHelper: CanChangeState (Iris + Bao policy) ──
[Fact]
public void CanChangeState_Iris_CanChangeAnyTask()
{
var agentTask = new WorkTask { Title = "test", IsAgentTask = true, Source = "iris" };
var normalTask = new WorkTask { Title = "test", IsAgentTask = false, Source = "bao" };
Assert.True(TaskStateHelper.CanChangeState("iris", agentTask));
Assert.True(TaskStateHelper.CanChangeState("iris", normalTask));
}
[Fact]
public void CanChangeState_Bao_CanChangeAnyTask()
{
var agentTask = new WorkTask { Title = "test", IsAgentTask = true, Source = "iris" };
var normalTask = new WorkTask { Title = "test", IsAgentTask = false, Source = "bao" };
Assert.True(TaskStateHelper.CanChangeState("bao", agentTask));
Assert.True(TaskStateHelper.CanChangeState("bao", normalTask));
}
[Fact]
public void CanChangeState_SubAgents_NeverAllowed()
{
var task = new WorkTask { Title = "test", IsAgentTask = false, Source = "bao" };
Assert.False(TaskStateHelper.CanChangeState("programmer", task));
Assert.False(TaskStateHelper.CanChangeState("reviewer", task));
Assert.False(TaskStateHelper.CanChangeState("architekt", task));
}
[Fact]
public void CanChangeState_SubAgents_NeverAllowed_EvenForAgentTasks()
{
var agentTask = new WorkTask { Title = "test", IsAgentTask = true, Source = "iris" };
Assert.False(TaskStateHelper.CanChangeState("programmer", agentTask));
Assert.False(TaskStateHelper.CanChangeState("reviewer", agentTask));
Assert.False(TaskStateHelper.CanChangeState("architekt", agentTask));
}
[Fact]
public void CanChangeState_NexusSystem_IsAllowed()
{
var task = new WorkTask { Title = "test", IsAgentTask = false };
Assert.True(TaskStateHelper.CanChangeState("nexus-system", task));
var agentTask = new WorkTask { Title = "test", IsAgentTask = true };
Assert.True(TaskStateHelper.CanChangeState("nexus-system", agentTask));
}
[Fact]
public void CanChangeState_UnknownCaller_Rejected()
{
var task = new WorkTask { Title = "test", IsAgentTask = false };
var agentTask = new WorkTask { Title = "test", IsAgentTask = true };
Assert.False(TaskStateHelper.CanChangeState("", task));
Assert.False(TaskStateHelper.CanChangeState("", agentTask));
Assert.False(TaskStateHelper.CanChangeState("unknown", task));
Assert.False(TaskStateHelper.CanChangeState(null, task));
}
// ── TaskStateHelper: CanEditContent ──
[Fact]
public void CanEditContent_Iris_IsAllowed()
{
Assert.True(TaskStateHelper.CanEditContent("iris"));
}
[Fact]
public void CanEditContent_Bao_IsAllowed()
{
Assert.True(TaskStateHelper.CanEditContent("bao"));
}
[Fact]
public void CanEditContent_SubAgents_AreAllowed()
{
Assert.True(TaskStateHelper.CanEditContent("programmer"));
Assert.True(TaskStateHelper.CanEditContent("reviewer"));
Assert.True(TaskStateHelper.CanEditContent("architekt"));
}
[Fact]
public void CanEditContent_NexusSystem_IsAllowed()
{
Assert.True(TaskStateHelper.CanEditContent("nexus-system"));
}
[Fact]
public void CanEditContent_UnknownCaller_Rejected()
{
Assert.False(TaskStateHelper.CanEditContent(""));
Assert.False(TaskStateHelper.CanEditContent(null));
Assert.False(TaskStateHelper.CanEditContent(" "));
}
}