v0.23.2 bfd5eb4

move_pane_to_tab_test.go RawHistoryFolder

1package usecase
2
3import (
4	"fmt"
5	"testing"
6
7	"github.com/bnema/dumber/internal/domain/entity"
8	"github.com/stretchr/testify/require"
9)
10
11func TestMovePaneToTab_MoveToExistingTab(t *testing.T) {
12	id := newTestIDGen()
13	uc := NewMovePaneToTabUseCase(id)
14
15	tabs := entity.NewTabList()
16
17	paneA := entity.NewPane(entity.PaneID("pA"))
18	tabA := entity.NewTab(entity.TabID("tA"), entity.WorkspaceID("wA"), paneA)
19	tabs.Add(tabA)
20
21	paneB := entity.NewPane(entity.PaneID("pB"))
22	tabB := entity.NewTab(entity.TabID("tB"), entity.WorkspaceID("wB"), paneB)
23	tabs.Add(tabB)
24	// Ensure tabB active pane is paneB.
25	tabB.Workspace.ActivePaneID = paneB.ID
26
27	out, err := uc.Execute(MovePaneToTabInput{
28		TabList:      tabs,
29		SourceTabID:  tabA.ID,
30		SourcePaneID: paneA.ID,
31		TargetTabID:  tabB.ID,
32	})
33	require.NoError(t, err)
34	require.True(t, out.SourceTabClosed)
35	require.False(t, out.NewTabCreated)
36	require.Equal(t, tabB.ID, out.TargetTab.ID)
37	require.NotNil(t, out.MovedPaneNode)
38
39	require.Nil(t, tabs.Find(tabA.ID))
40	// Inserted as split in tabB.
41	require.NotNil(t, tabB.Workspace.Root)
42	require.True(t, tabB.Workspace.Root.IsSplit())
43	require.Equal(t, paneB.ID, tabB.Workspace.Root.Left().Pane.ID)
44	require.Equal(t, paneA.ID, tabB.Workspace.Root.Right().Pane.ID)
45	// Active pane becomes moved pane.
46	require.Equal(t, paneA.ID, tabB.Workspace.ActivePaneID)
47}
48
49func TestMovePaneToTab_MoveCreatesNewTabWhenOnlyOneTab(t *testing.T) {
50	id := newTestIDGen()
51	uc := NewMovePaneToTabUseCase(id)
52
53	tabs := entity.NewTabList()
54	paneA := entity.NewPane(entity.PaneID("pA"))
55	tabA := entity.NewTab(entity.TabID("tA"), entity.WorkspaceID("wA"), paneA)
56	tabs.Add(tabA)
57
58	out, err := uc.Execute(MovePaneToTabInput{
59		TabList:      tabs,
60		SourceTabID:  tabA.ID,
61		SourcePaneID: paneA.ID,
62		TargetTabID:  "",
63	})
64	require.NoError(t, err)
65	require.True(t, out.NewTabCreated)
66	require.True(t, out.SourceTabClosed)
67	require.Equal(t, 1, tabs.Count())
68	require.Equal(t, paneA.ID, out.TargetTab.Workspace.ActivePaneID)
69	require.NotNil(t, out.TargetTab.Workspace.Root)
70	require.True(t, out.TargetTab.Workspace.Root.IsLeaf())
71	require.Equal(t, paneA.ID, out.TargetTab.Workspace.Root.Pane.ID)
72}
73
74func TestMovePaneToTab_CannotMoveToSameTab(t *testing.T) {
75	uc := NewMovePaneToTabUseCase(newTestIDGen())
76	abs := entity.NewTabList()
77	pane := entity.NewPane(entity.PaneID("pA"))
78	tab := entity.NewTab(entity.TabID("tA"), entity.WorkspaceID("wA"), pane)
79	abs.Add(tab)
80
81	_, err := uc.Execute(MovePaneToTabInput{
82		TabList:      abs,
83		SourceTabID:  tab.ID,
84		SourcePaneID: pane.ID,
85		TargetTabID:  tab.ID,
86	})
87	require.Error(t, err)
88}
89
90func TestMovePaneToTab_SourcePaneNotFound(t *testing.T) {
91	uc := NewMovePaneToTabUseCase(newTestIDGen())
92	tabs := entity.NewTabList()
93	pane := entity.NewPane(entity.PaneID("pA"))
94	tab := entity.NewTab(entity.TabID("tA"), entity.WorkspaceID("wA"), pane)
95	tabs.Add(tab)
96
97	_, err := uc.Execute(MovePaneToTabInput{
98		TabList:      tabs,
99		SourceTabID:  tab.ID,
100		SourcePaneID: entity.PaneID("missing"),
101		TargetTabID:  entity.TabID("tB"),
102	})
103	require.Error(t, err)
104}
105
106func TestMovePaneToTab_MoveFromSplitClosesSourceTabIfLastPane(t *testing.T) {
107	id := newTestIDGen()
108	uc := NewMovePaneToTabUseCase(id)
109
110	tabs := entity.NewTabList()
111
112	// Source workspace: split with two panes; move one, leaving one.
113	paneLeft := entity.NewPane(entity.PaneID("pL"))
114	paneRight := entity.NewPane(entity.PaneID("pR"))
115	source := entity.NewTab(entity.TabID("tA"), entity.WorkspaceID("wA"), paneLeft)
116	// Build a split root manually.
117	source.Workspace.Root = &entity.PaneNode{
118		ID:         "root",
119		SplitDir:   entity.SplitHorizontal,
120		SplitRatio: 0.5,
121		Children: []*entity.PaneNode{
122			{ID: string(paneLeft.ID), Pane: paneLeft},
123			{ID: string(paneRight.ID), Pane: paneRight},
124		},
125	}
126	source.Workspace.Root.Children[0].Parent = source.Workspace.Root
127	source.Workspace.Root.Children[1].Parent = source.Workspace.Root
128	source.Workspace.ActivePaneID = paneRight.ID
129	tabs.Add(source)
130
131	targetPane := entity.NewPane(entity.PaneID("pT"))
132	target := entity.NewTab(entity.TabID("tB"), entity.WorkspaceID("wB"), targetPane)
133	tabs.Add(target)
134
135	out, err := uc.Execute(MovePaneToTabInput{
136		TabList:      tabs,
137		SourceTabID:  source.ID,
138		SourcePaneID: paneRight.ID,
139		TargetTabID:  target.ID,
140	})
141	require.NoError(t, err)
142	require.False(t, out.SourceTabClosed)
143	// Source should now be single leaf.
144	require.Equal(t, 1, source.Workspace.PaneCount())
145	require.NotNil(t, source.Workspace.Root)
146	require.True(t, source.Workspace.Root.IsLeaf())
147	require.Equal(t, paneLeft.ID, source.Workspace.Root.Pane.ID)
148}
149
150func TestMovePaneToTab_InsertsRightOfActiveEvenWhenActiveInStack(t *testing.T) {
151	id := newTestIDGen()
152	uc := NewMovePaneToTabUseCase(id)
153
154	tabs := entity.NewTabList()
155
156	paneA := entity.NewPane(entity.PaneID("pA"))
157	source := entity.NewTab(entity.TabID("tA"), entity.WorkspaceID("wA"), paneA)
158	tabs.Add(source)
159
160	// Target workspace: stacked container with two panes; active is second.
161	pane1 := entity.NewPane(entity.PaneID("p1"))
162	pane2 := entity.NewPane(entity.PaneID("p2"))
163	target := entity.NewTab(entity.TabID("tB"), entity.WorkspaceID("wB"), pane1)
164	stack := &entity.PaneNode{
165		ID:               "stack",
166		IsStacked:        true,
167		ActiveStackIndex: 1,
168		Children: []*entity.PaneNode{
169			{ID: string(pane1.ID), Pane: pane1},
170			{ID: string(pane2.ID), Pane: pane2},
171		},
172	}
173	stack.Children[0].Parent = stack
174	stack.Children[1].Parent = stack
175	target.Workspace.Root = stack
176	target.Workspace.ActivePaneID = pane2.ID
177	tabs.Add(target)
178
179	out, err := uc.Execute(MovePaneToTabInput{
180		TabList:      tabs,
181		SourceTabID:  source.ID,
182		SourcePaneID: paneA.ID,
183		TargetTabID:  target.ID,
184	})
185	require.NoError(t, err)
186	require.NotNil(t, out.TargetTab.Workspace.Root)
187	require.True(t, out.TargetTab.Workspace.Root.IsSplit())
188	// Left child should be the stack container.
189	require.True(t, out.TargetTab.Workspace.Root.Left().IsStacked)
190	// Right child is moved pane.
191	require.Equal(t, paneA.ID, out.TargetTab.Workspace.Root.Right().Pane.ID)
192}
193
194func newTestIDGen() func() string {
195	counter := 0
196	return func() string {
197		counter++
198		return fmt.Sprintf("id%d", counter)
199	}
200}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close