Forge
csharpdeeb25a2
1using CascadeIDE.Features.Chat;
2using CascadeIDE.Models.AgentChat;
3using Xunit;
4
5namespace CascadeIDE.Tests;
6
7public sealed class ChatSurfaceCompositorTests
8{
9 [Fact]
10 public void Compose_ForkedConversation_CreatesBranchLaneAndForkEdge()
11 {
12 var mainThread = Guid.NewGuid();
13 var branchThread = Guid.NewGuid();
14 var rootMessage = new ChatConversationMessage(Guid.NewGuid(), "user", "Надо продумать ADR", mainThread, null, 0);
15 var assistantMessage = new ChatConversationMessage(Guid.NewGuid(), "assistant", "Давай разложим варианты.", mainThread, null, 1);
16 var branchMessage = new ChatConversationMessage(Guid.NewGuid(), "user", "Отдельно исследую Skia path", branchThread, assistantMessage.MessageId, 2);
17
18 var snapshot = new ChatSurfaceCompositor().Compose(new ChatSurfaceIntent(
19 [rootMessage, assistantMessage, branchMessage],
20 ActiveClarificationBatch: null,
21 SelectedMessageIndex: 2,
22 MainThreadId: mainThread,
23 ActiveThreadId: branchThread,
24 ThreadBranchHint: "Ветка Skia"));
25
26 Assert.Equal(2, snapshot.State.Threads.Count);
27 Assert.Equal(2, snapshot.Layout.Lanes.Count);
28
29 var branchLane = Assert.Single(snapshot.Layout.Lanes, lane => lane.Thread.ThreadId == branchThread);
30 Assert.Equal(1, branchLane.Thread.Depth);
31 Assert.Contains(branchLane.Entries, entry => entry.StartsBranch);
32 Assert.Contains(snapshot.State.Edges, edge => edge.Kind == "fork");
33 Assert.Contains(snapshot.Layout.Overview, item => item.ThreadId == branchThread && item.IsActive);
34
35 var branchOverview = Assert.Single(snapshot.Layout.Overview, item => item.ThreadId == branchThread);
36 Assert.Contains("Skia", branchOverview.Summary, StringComparison.OrdinalIgnoreCase);
37 }
38
39 [Fact]
40 public void Compose_SingleThreadOverview_UsesLastAssistantMessageAsSummary()
41 {
42 var threadId = Guid.NewGuid();
43 var snapshot = new ChatSurfaceCompositor().Compose(new ChatSurfaceIntent(
44 [
45 new ChatConversationMessage(Guid.NewGuid(), "user", "Как сделать topic cards?", threadId, null, 0),
46 new ChatConversationMessage(Guid.NewGuid(), "assistant", "Картотека: заголовок и короткая сводка.", threadId, null, 1)
47 ],
48 ActiveClarificationBatch: null,
49 SelectedMessageIndex: -1,
50 MainThreadId: threadId,
51 ActiveThreadId: threadId,
52 ThreadBranchHint: null));
53
54 var overview = Assert.Single(snapshot.Layout.Overview);
55 Assert.Contains("картотека", overview.Summary, StringComparison.OrdinalIgnoreCase);
56 }
57
58 [Fact]
59 public void Compose_ActiveClarification_AddsConfirmationNodeToActiveThread()
60 {
61 var threadId = Guid.NewGuid();
62 var batch = new ClarificationBatch(
63 Guid.NewGuid(),
64 [new ClarificationItem("scope", "Где показать preview?")],
65 "Нужно уточнить решение");
66
67 var snapshot = new ChatSurfaceCompositor().Compose(new ChatSurfaceIntent(
68 [new ChatConversationMessage(Guid.NewGuid(), "assistant", "Есть два пути.", threadId, null, 0)],
69 batch,
70 SelectedMessageIndex: -1,
71 MainThreadId: threadId,
72 ActiveThreadId: threadId,
73 ThreadBranchHint: null));
74
75 var confirmation = Assert.Single(snapshot.State.Confirmations);
76 Assert.Equal(threadId, confirmation.ThreadId);
77 Assert.True(confirmation.IsActive);
78 Assert.Contains("Где показать preview?", confirmation.Body);
79
80 var lane = Assert.Single(snapshot.Layout.Lanes);
81 Assert.Contains(lane.Entries, entry => entry.Kind == ChatSurfaceEntryKind.Confirmation && entry.IsPending);
82 Assert.Contains(snapshot.State.Edges, edge => edge.Kind == "ask");
83 }
84}
85
View only · write via MCP/CIDE