fix: restore green test suite across all projects
* TaskRepository.UpdateAsync defensively detaches any locally tracked entity with the same Id before attaching the patched copy, preventing EF identity conflicts when callers load via AsNoTracking and write back through the same DbContext (surfaced by ExternalMcpService UpdateTask integration tests). * TasksIslandViewModel auto-collapse now only fires for Finalized planning parents that are not yet Done. Active-phase parents stay expanded while the user is editing the plan, and Done parents stay expanded so all completed children land in CompletedItems alongside the parent. * Update three Ui.Tests fakes (ConflictResolution, PlanningDiff, DetailsIslandPlanning) to implement the two new IWorkerClient members (OpenInteractiveTerminalAsync, QueuePlanningSubtasksAsync). * Rewrite StreamLineFormatterTests to exercise the current assistant/user/result/system message format instead of the legacy stream_event parsing that was removed in the formatter rewrite. * Align AppSettingsRepository seed-default assertion with the permission-mode default that flipped from bypassPermissions to auto. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,38 +6,38 @@ public class StreamLineFormatterTests
|
||||
{
|
||||
private readonly StreamLineFormatter _formatter = new();
|
||||
|
||||
// --- Text deltas ---
|
||||
// --- Assistant text blocks ---
|
||||
|
||||
[Fact]
|
||||
public void FormatLine_TextDelta_ReturnsTextContent()
|
||||
public void FormatLine_AssistantTextBlock_ReturnsTextContent()
|
||||
{
|
||||
var line = """{"type":"stream_event","event":{"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello world"}}}""";
|
||||
Assert.Equal("Hello world", _formatter.FormatLine(line));
|
||||
var line = """{"type":"assistant","message":{"content":[{"type":"text","text":"Hello world"}]}}""";
|
||||
Assert.Equal("Hello world\n", _formatter.FormatLine(line));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatLine_ConsecutiveTextDeltas_ReturnEachDelta()
|
||||
public void FormatLine_AssistantConsecutiveTextBlocks_ReturnEachAppended()
|
||||
{
|
||||
var line1 = """{"type":"stream_event","event":{"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello "}}}""";
|
||||
var line2 = """{"type":"stream_event","event":{"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"world"}}}""";
|
||||
Assert.Equal("Hello ", _formatter.FormatLine(line1));
|
||||
Assert.Equal("world", _formatter.FormatLine(line2));
|
||||
var line1 = """{"type":"assistant","message":{"content":[{"type":"text","text":"Hello "}]}}""";
|
||||
var line2 = """{"type":"assistant","message":{"content":[{"type":"text","text":"world"}]}}""";
|
||||
Assert.Equal("Hello \n", _formatter.FormatLine(line1));
|
||||
Assert.Equal("world\n", _formatter.FormatLine(line2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatLine_ContentBlockStop_ReturnsNewline()
|
||||
public void FormatLine_AssistantThinkingBlock_IsFiltered()
|
||||
{
|
||||
var line = """{"type":"stream_event","event":{"type":"content_block_stop","index":0}}""";
|
||||
Assert.Equal("\n", _formatter.FormatLine(line));
|
||||
var line = """{"type":"assistant","message":{"content":[{"type":"thinking","text":"hidden"}]}}""";
|
||||
Assert.Null(_formatter.FormatLine(line));
|
||||
}
|
||||
|
||||
// --- Tool use, result, system, fallback ---
|
||||
|
||||
[Fact]
|
||||
public void FormatLine_ToolUseStart_ReturnsToolNameLine()
|
||||
public void FormatLine_AssistantToolUseBlock_ReturnsToolNameLine()
|
||||
{
|
||||
var line = """{"type":"stream_event","event":{"type":"content_block_start","index":1,"content_block":{"type":"tool_use","id":"x","name":"bash"}}}""";
|
||||
Assert.Equal("\n[Tool: bash]\n", _formatter.FormatLine(line));
|
||||
var line = """{"type":"assistant","message":{"content":[{"type":"tool_use","id":"x","name":"Bash","input":{"command":"ls"}}]}}""";
|
||||
Assert.Equal("[Bash] $ ls\n", _formatter.FormatLine(line));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -58,13 +58,13 @@ public class StreamLineFormatterTests
|
||||
public void FormatLine_ApiRetry_ReturnsRetryNotice()
|
||||
{
|
||||
var line = """{"type":"system","subtype":"api_retry"}""";
|
||||
Assert.Equal("\n[Retrying API call...]\n", _formatter.FormatLine(line));
|
||||
Assert.Equal("[Retrying API call...]\n", _formatter.FormatLine(line));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatLine_SystemNonRetry_ReturnsNull()
|
||||
public void FormatLine_SystemUnknownSubtype_ReturnsNull()
|
||||
{
|
||||
var line = """{"type":"system","subtype":"init"}""";
|
||||
var line = """{"type":"system","subtype":"some_unknown_subtype"}""";
|
||||
Assert.Null(_formatter.FormatLine(line));
|
||||
}
|
||||
|
||||
@@ -98,8 +98,8 @@ public class StreamLineFormatterTests
|
||||
{
|
||||
var lines = new[]
|
||||
{
|
||||
"""{"type":"stream_event","event":{"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}}""",
|
||||
"""{"type":"stream_event","event":{"type":"content_block_start","index":1,"content_block":{"type":"tool_use","id":"x","name":"bash"}}}""",
|
||||
"""{"type":"assistant","message":{"content":[{"type":"text","text":"Hello"}]}}""",
|
||||
"""{"type":"assistant","message":{"content":[{"type":"tool_use","id":"x","name":"Bash","input":{"command":"ls"}}]}}""",
|
||||
"""{"type":"result","result":"Done."}""",
|
||||
};
|
||||
var file = Path.GetTempFileName();
|
||||
@@ -108,7 +108,7 @@ public class StreamLineFormatterTests
|
||||
File.WriteAllLines(file, lines);
|
||||
var result = _formatter.FormatFile(file);
|
||||
Assert.Contains("Hello", result);
|
||||
Assert.Contains("[Tool: bash]", result);
|
||||
Assert.Contains("[Bash]", result);
|
||||
Assert.Contains("Done.", result);
|
||||
}
|
||||
finally
|
||||
@@ -121,7 +121,7 @@ public class StreamLineFormatterTests
|
||||
public void FormatFile_TrimsLargeContent()
|
||||
{
|
||||
var chunk = new string('x', 1000);
|
||||
var line = "{\"type\":\"stream_event\",\"event\":{\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"" + chunk + "\"}}}";
|
||||
var line = "{\"type\":\"assistant\",\"message\":{\"content\":[{\"type\":\"text\",\"text\":\"" + chunk + "\"}]}}";
|
||||
var lines = Enumerable.Repeat(line, 65).ToArray();
|
||||
var file = Path.GetTempFileName();
|
||||
try
|
||||
|
||||
@@ -48,6 +48,8 @@ public class ConflictResolutionViewModelTests
|
||||
public Task<CombinedDiffResultDto?> BuildPlanningIntegrationBranchAsync(string planningTaskId, string targetBranch) =>
|
||||
Task.FromResult<CombinedDiffResultDto?>(null);
|
||||
public Task MergeAllPlanningAsync(string planningTaskId, string targetBranch) => Task.CompletedTask;
|
||||
public Task OpenInteractiveTerminalAsync(string taskId, CancellationToken ct = default) => Task.CompletedTask;
|
||||
public Task QueuePlanningSubtasksAsync(string parentTaskId, CancellationToken ct = default) => Task.CompletedTask;
|
||||
|
||||
public Task ContinuePlanningMergeAsync(string planningTaskId)
|
||||
{
|
||||
|
||||
@@ -80,6 +80,8 @@ public class DetailsIslandPlanningTests : IDisposable
|
||||
public Task MergeAllPlanningAsync(string planningTaskId, string targetBranch) => Task.CompletedTask;
|
||||
public Task ContinuePlanningMergeAsync(string planningTaskId) => Task.CompletedTask;
|
||||
public Task AbortPlanningMergeAsync(string planningTaskId) => Task.CompletedTask;
|
||||
public Task OpenInteractiveTerminalAsync(string taskId, CancellationToken ct = default) => Task.CompletedTask;
|
||||
public Task QueuePlanningSubtasksAsync(string parentTaskId, CancellationToken ct = default) => Task.CompletedTask;
|
||||
}
|
||||
|
||||
private sealed class NullServiceProvider : IServiceProvider
|
||||
|
||||
@@ -47,6 +47,8 @@ public class PlanningDiffViewModelTests
|
||||
public Task MergeAllPlanningAsync(string planningTaskId, string targetBranch) => Task.CompletedTask;
|
||||
public Task ContinuePlanningMergeAsync(string planningTaskId) => Task.CompletedTask;
|
||||
public Task AbortPlanningMergeAsync(string planningTaskId) => Task.CompletedTask;
|
||||
public Task OpenInteractiveTerminalAsync(string taskId, CancellationToken ct = default) => Task.CompletedTask;
|
||||
public Task QueuePlanningSubtasksAsync(string parentTaskId, CancellationToken ct = default) => Task.CompletedTask;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user