using ClaudeDo.Ui.Helpers; using ClaudeDo.Ui.ViewModels.Islands; namespace ClaudeDo.Ui.Tests.Helpers; public class StreamLineFormatterTests { private readonly StreamLineFormatter _formatter = new(); private (LogKind Kind, string Text) Single(string line) => Assert.Single(_formatter.FormatLine(line)!); // --- Assistant text blocks --- [Fact] public void FormatLine_AssistantTextBlock_ReturnsClaudeEntry() { var line = """{"type":"assistant","message":{"content":[{"type":"text","text":"Hello world"}]}}"""; Assert.Equal((LogKind.Claude, "Hello world"), Single(line)); } [Fact] public void FormatLine_AssistantThinkingBlock_IsFiltered() { var line = """{"type":"assistant","message":{"content":[{"type":"thinking","text":"hidden"}]}}"""; Assert.Null(_formatter.FormatLine(line)); } [Fact] public void FormatLine_MixedBlocks_KeepOrderAndKinds() { var line = """{"type":"assistant","message":{"content":[{"type":"text","text":"Fixing it."},{"type":"tool_use","id":"x","name":"Edit","input":{"file_path":"C:/repo/src/Foo.cs"}}]}}"""; Assert.Equal( [(LogKind.Claude, "Fixing it."), (LogKind.Edit, "[Edit] Foo.cs")], _formatter.FormatLine(line)); } // --- Tool use --- [Fact] public void FormatLine_AssistantToolUseBlock_ReturnsToolEntry() { var line = """{"type":"assistant","message":{"content":[{"type":"tool_use","id":"x","name":"Bash","input":{"command":"ls"}}]}}"""; Assert.Equal((LogKind.Tool, "[Bash] $ ls"), Single(line)); } [Theory] [InlineData("Write")] [InlineData("NotebookEdit")] public void FormatLine_FileMutatingTools_AreEditKind(string tool) { var line = $$$"""{"type":"assistant","message":{"content":[{"type":"tool_use","id":"x","name":"{{{tool}}}","input":{"file_path":"a/b.txt"}}]}}"""; Assert.Equal((LogKind.Edit, $"[{tool}] b.txt"), Single(line)); } [Fact] public void FormatLine_LongBashCommand_IsNotCutAt120Chars() { var cmd = "cd \\\"C:/Private/.claudedo-worktrees/claude-do/385-unit-branch-teil-1-branch-naming-basis-b\\\" && dotnet build ClaudeDo.slnx -c Release --no-restore -v minimal"; var line = $$$"""{"type":"assistant","message":{"content":[{"type":"tool_use","id":"x","name":"Bash","input":{"command":"{{{cmd}}}"}}]}}"""; var (_, text) = Single(line); Assert.EndsWith("-v minimal", text); } // --- Tool results --- [Fact] public void FormatLine_ToolResult_IsToolResultKind() { var line = """{"type":"user","message":{"content":[{"type":"tool_result","content":"Build succeeded."}]}}"""; Assert.Equal((LogKind.ToolResult, "→ Build succeeded."), Single(line)); } [Fact] public void FormatLine_ToolResultError_IsStderrKind() { var line = """{"type":"user","message":{"content":[{"type":"tool_result","is_error":true,"content":"boom"}]}}"""; Assert.Equal((LogKind.Stderr, "→ error: boom"), Single(line)); } // --- Result, system, fallback --- [Fact] public void FormatLine_InputJsonDelta_ReturnsNull() { var line = """{"type":"stream_event","event":{"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"cmd\":"}}}"""; Assert.Null(_formatter.FormatLine(line)); } [Fact] public void FormatLine_Result_ReturnsDoneEntry() { var line = """{"type":"result","result":"Done."}"""; Assert.Equal((LogKind.Done, "--- Result ---\nDone."), Single(line)); } [Fact] public void FormatLine_ApiRetry_ReturnsSysEntry() { var line = """{"type":"system","subtype":"api_retry"}"""; Assert.Equal((LogKind.Sys, "[Retrying API call...]"), Single(line)); } [Fact] public void FormatLine_SystemUnknownSubtype_ReturnsNull() { var line = """{"type":"system","subtype":"some_unknown_subtype"}"""; Assert.Null(_formatter.FormatLine(line)); } [Fact] public void FormatLine_AssistantType_ReturnsNull() { var line = """{"type":"assistant","message":{}}"""; Assert.Null(_formatter.FormatLine(line)); } [Fact] public void FormatLine_MalformedJson_ReturnsRawStdoutEntry() { Assert.Equal((LogKind.Stdout, "not json at all"), Single("not json at all")); } [Fact] public void FormatLine_MessageStartAndDelta_ReturnsNull() { var start = """{"type":"stream_event","event":{"type":"message_start","message":{}}}"""; var delta = """{"type":"stream_event","event":{"type":"message_delta","delta":{}}}"""; Assert.Null(_formatter.FormatLine(start)); Assert.Null(_formatter.FormatLine(delta)); } // --- Line splitting --- [Fact] public void FromEntries_SplitsMultilineText_KeepingKind_AndDroppingBlanks() { var lines = LogLineViewModel.FromEntries([(LogKind.Done, "--- Result ---\n\nDone.\r\n")]).ToList(); Assert.Equal(["--- Result ---", "Done."], lines.Select(l => l.Text)); Assert.All(lines, l => Assert.Equal(LogKind.Done, l.Kind)); } }