manage_panes_close_stack_test.go RawHistoryFolder
1package usecase
2
3import (
4 "context"
5 "testing"
6
7 "github.com/bnema/dumber/internal/domain/entity"
8)
9
10func TestManagePanesUseCase_CloseStackedPane_RemovesFromStackWithMoreThanTwo(t *testing.T) {
11 uc := NewManagePanesUseCase(func() string { return "id" }, nil)
12 ctx := context.Background()
13
14 // Create a stack with 3 panes
15 a := leaf("a")
16 b := leaf("b")
17 c := leaf("c")
18 stackNode := stack(a, b, c)
19 stackNode.ActiveStackIndex = 1 // b is active
20
21 ws := &entity.Workspace{Root: stackNode, ActivePaneID: b.Pane.ID}
22
23 // Close pane b (the middle one)
24 result, err := uc.Close(ctx, ws, b)
25 if err != nil {
26 t.Fatalf("unexpected error: %v", err)
27 }
28
29 // Stack should remain with 2 panes
30 if !ws.Root.IsStacked {
31 t.Fatalf("root should still be a stack")
32 }
33 if len(ws.Root.Children) != 2 {
34 t.Fatalf("stack should have 2 children, got %d", len(ws.Root.Children))
35 }
36 if got := panesInOrder(ws.Root); got != "a,c" {
37 t.Fatalf("remaining panes=%s, want a,c", got)
38 }
39
40 // Result should be the stack node
41 if result != stackNode {
42 t.Fatalf("expected stack node to be returned")
43 }
44}
45
46func TestManagePanesUseCase_CloseStackedPane_DissolvesStackWithTwo(t *testing.T) {
47 uc := NewManagePanesUseCase(func() string { return "id" }, nil)
48 ctx := context.Background()
49
50 // Create a stack with 2 panes
51 a := leaf("a")
52 b := leaf("b")
53 stackNode := stack(a, b)
54 stackNode.ActiveStackIndex = 1 // b is active
55
56 ws := &entity.Workspace{Root: stackNode, ActivePaneID: b.Pane.ID}
57
58 // Close pane b
59 result, err := uc.Close(ctx, ws, b)
60 if err != nil {
61 t.Fatalf("unexpected error: %v", err)
62 }
63
64 // Stack should be dissolved, remaining pane becomes root
65 if ws.Root.IsStacked {
66 t.Fatalf("root should no longer be a stack")
67 }
68 if !ws.Root.IsLeaf() {
69 t.Fatalf("root should be a leaf")
70 }
71 if ws.Root.Pane.ID != "a" {
72 t.Fatalf("remaining pane should be a, got %s", ws.Root.Pane.ID)
73 }
74
75 // Result should be the remaining pane
76 if result.Pane.ID != "a" {
77 t.Fatalf("expected remaining pane a to be returned")
78 }
79
80 // Active pane should update to remaining pane
81 if ws.ActivePaneID != "a" {
82 t.Fatalf("active pane should be a, got %s", ws.ActivePaneID)
83 }
84}
85
86func TestManagePanesUseCase_CloseStackedPane_UpdatesActivePaneWhenClosingActive(t *testing.T) {
87 uc := NewManagePanesUseCase(func() string { return "id" }, nil)
88 ctx := context.Background()
89
90 // Create a stack with 3 panes, middle one is active
91 a := leaf("a")
92 b := leaf("b")
93 c := leaf("c")
94 stackNode := stack(a, b, c)
95 stackNode.ActiveStackIndex = 1 // b is active
96
97 ws := &entity.Workspace{Root: stackNode, ActivePaneID: b.Pane.ID}
98
99 // Close pane b (the active one)
100 _, err := uc.Close(ctx, ws, b)
101 if err != nil {
102 t.Fatalf("unexpected error: %v", err)
103 }
104
105 // Active pane should be updated (to the pane at the new active index)
106 if ws.ActivePaneID == "b" {
107 t.Fatalf("active pane should not be the closed pane b")
108 }
109 // Should be either a or c depending on new ActiveStackIndex
110 if ws.ActivePaneID != "a" && ws.ActivePaneID != "c" {
111 t.Fatalf("active pane should be a or c, got %s", ws.ActivePaneID)
112 }
113}
114
115func TestManagePanesUseCase_CloseStackedPane_PreservesActivePaneWhenClosingNonActive(t *testing.T) {
116 uc := NewManagePanesUseCase(func() string { return "id" }, nil)
117 ctx := context.Background()
118
119 // Create a stack with 3 panes, first one is active
120 a := leaf("a")
121 b := leaf("b")
122 c := leaf("c")
123 stackNode := stack(a, b, c)
124 stackNode.ActiveStackIndex = 0 // a is active
125
126 ws := &entity.Workspace{Root: stackNode, ActivePaneID: a.Pane.ID}
127
128 // Close pane c (not the active one)
129 _, err := uc.Close(ctx, ws, c)
130 if err != nil {
131 t.Fatalf("unexpected error: %v", err)
132 }
133
134 // Active pane should remain a
135 if ws.ActivePaneID != "a" {
136 t.Fatalf("active pane should still be a, got %s", ws.ActivePaneID)
137 }
138}
139
140func TestManagePanesUseCase_CloseStackedPane_DissolvesNestedStack(t *testing.T) {
141 uc := NewManagePanesUseCase(func() string { return "id" }, nil)
142 ctx := context.Background()
143
144 // Create a split with a stack on the left
145 a := leaf("a")
146 b := leaf("b")
147 stackNode := stack(a, b)
148 stackNode.ActiveStackIndex = 0
149
150 c := leaf("c")
151 root := split(entity.SplitHorizontal, stackNode, c)
152
153 ws := &entity.Workspace{Root: root, ActivePaneID: a.Pane.ID}
154
155 // Close pane a from the stack
156 _, err := uc.Close(ctx, ws, a)
157 if err != nil {
158 t.Fatalf("unexpected error: %v", err)
159 }
160
161 // Root should still be a split
162 if !ws.Root.IsSplit() {
163 t.Fatalf("root should still be a split")
164 }
165
166 // Left child should now be the remaining pane b (not a stack)
167 left := ws.Root.Left()
168 if left.IsStacked {
169 t.Fatalf("left child should no longer be a stack")
170 }
171 if !left.IsLeaf() || left.Pane.ID != "b" {
172 t.Fatalf("left child should be leaf b, got %v", left)
173 }
174
175 // Right child should still be c
176 right := ws.Root.Right()
177 if !right.IsLeaf() || right.Pane.ID != "c" {
178 t.Fatalf("right child should be leaf c")
179 }
180
181 // Active pane should update to b
182 if ws.ActivePaneID != "b" {
183 t.Fatalf("active pane should be b, got %s", ws.ActivePaneID)
184 }
185}
186
187func TestManagePanesUseCase_CloseStackedPane_ClosingFirstPaneUpdatesIndex(t *testing.T) {
188 uc := NewManagePanesUseCase(func() string { return "id" }, nil)
189 ctx := context.Background()
190
191 // Create a stack with 3 panes, first one is active
192 a := leaf("a")
193 b := leaf("b")
194 c := leaf("c")
195 stackNode := stack(a, b, c)
196 stackNode.ActiveStackIndex = 0 // a is active
197
198 ws := &entity.Workspace{Root: stackNode, ActivePaneID: a.Pane.ID}
199
200 // Close pane a (the first and active one)
201 _, err := uc.Close(ctx, ws, a)
202 if err != nil {
203 t.Fatalf("unexpected error: %v", err)
204 }
205
206 // Stack should have 2 panes remaining
207 if len(ws.Root.Children) != 2 {
208 t.Fatalf("stack should have 2 children, got %d", len(ws.Root.Children))
209 }
210 if got := panesInOrder(ws.Root); got != "b,c" {
211 t.Fatalf("remaining panes=%s, want b,c", got)
212 }
213
214 // Active pane should be updated
215 if ws.ActivePaneID == "a" {
216 t.Fatalf("active pane should not be the closed pane a")
217 }
218}
219
220func TestManagePanesUseCase_CloseStackedPane_ClosingLastPaneUpdatesIndex(t *testing.T) {
221 uc := NewManagePanesUseCase(func() string { return "id" }, nil)
222 ctx := context.Background()
223
224 // Create a stack with 3 panes, last one is active
225 a := leaf("a")
226 b := leaf("b")
227 c := leaf("c")
228 stackNode := stack(a, b, c)
229 stackNode.ActiveStackIndex = 2 // c is active
230
231 ws := &entity.Workspace{Root: stackNode, ActivePaneID: c.Pane.ID}
232
233 // Close pane c (the last and active one)
234 _, err := uc.Close(ctx, ws, c)
235 if err != nil {
236 t.Fatalf("unexpected error: %v", err)
237 }
238
239 // Stack should have 2 panes remaining
240 if len(ws.Root.Children) != 2 {
241 t.Fatalf("stack should have 2 children, got %d", len(ws.Root.Children))
242 }
243 if got := panesInOrder(ws.Root); got != "a,b" {
244 t.Fatalf("remaining panes=%s, want a,b", got)
245 }
246
247 // Active pane should be updated to the new last pane
248 if ws.ActivePaneID == "c" {
249 t.Fatalf("active pane should not be the closed pane c")
250 }
251}