main 5041353

keybindings_test.go RawHistoryFolder

1package usecase_test
2
3import (
4	"context"
5	"errors"
6	"testing"
7
8	"github.com/stretchr/testify/assert"
9	"github.com/stretchr/testify/mock"
10	"github.com/stretchr/testify/require"
11
12	"github.com/bnema/dumber/internal/application/port"
13	"github.com/bnema/dumber/internal/application/port/mocks"
14	"github.com/bnema/dumber/internal/application/usecase"
15)
16
17func TestGetKeybindingsUseCase_Execute(t *testing.T) {
18	t.Run("returns keybindings from provider", func(t *testing.T) {
19		// Arrange
20		mockProvider := mocks.NewMockKeybindingsProvider(t)
21		expected := port.KeybindingsConfig{
22			Groups: []port.KeybindingGroup{
23				{
24					Mode:        "global",
25					DisplayName: "Global Shortcuts",
26					Bindings: []port.KeybindingEntry{
27						{Action: "close_pane", Keys: []string{"ctrl+w"}},
28					},
29				},
30			},
31		}
32		mockProvider.EXPECT().GetKeybindings(mock.Anything).Return(expected, nil)
33
34		uc := usecase.NewGetKeybindingsUseCase(mockProvider)
35
36		// Act
37		result, err := uc.Execute(context.Background())
38
39		// Assert
40		require.NoError(t, err)
41		assert.Equal(t, expected, result)
42		mock.AssertExpectationsForObjects(t, mockProvider)
43	})
44
45	t.Run("returns error when provider fails", func(t *testing.T) {
46		// Arrange
47		mockProvider := mocks.NewMockKeybindingsProvider(t)
48		mockProvider.EXPECT().GetKeybindings(mock.Anything).Return(port.KeybindingsConfig{}, errors.New("provider error"))
49
50		uc := usecase.NewGetKeybindingsUseCase(mockProvider)
51
52		// Act
53		_, err := uc.Execute(context.Background())
54
55		// Assert
56		require.Error(t, err)
57		assert.Contains(t, err.Error(), "provider error")
58		mock.AssertExpectationsForObjects(t, mockProvider)
59	})
60
61	t.Run("returns error when provider is nil", func(t *testing.T) {
62		// Arrange
63		uc := usecase.NewGetKeybindingsUseCase(nil)
64
65		// Act
66		_, err := uc.Execute(context.Background())
67
68		// Assert
69		require.Error(t, err)
70		assert.Contains(t, err.Error(), "provider is nil")
71	})
72}
73
74func TestSetKeybindingUseCase_Execute(t *testing.T) {
75	t.Run("accepts vim mode", func(t *testing.T) {
76		mockProvider := mocks.NewMockKeybindingsProvider(t)
77		mockSaver := mocks.NewMockKeybindingsSaver(t)
78		req := port.SetKeybindingRequest{Mode: "vim", Action: "vim-scroll-down", Keys: []string{"j"}}
79		mockProvider.EXPECT().CheckConflicts(mock.Anything, req.Mode, req.Action, req.Keys).Return(nil, nil)
80		mockSaver.EXPECT().SetKeybinding(mock.Anything, req).Return(nil)
81
82		_, err := usecase.NewSetKeybindingUseCase(mockProvider, mockSaver).Execute(context.Background(), req)
83		require.NoError(t, err)
84	})
85
86	t.Run("successfully sets keybinding", func(t *testing.T) {
87		// Arrange
88		mockProvider := mocks.NewMockKeybindingsProvider(t)
89		mockSaver := mocks.NewMockKeybindingsSaver(t)
90		req := port.SetKeybindingRequest{
91			Mode:   "pane",
92			Action: "split-right",
93			Keys:   []string{"r"},
94		}
95		mockProvider.EXPECT().CheckConflicts(mock.Anything, req.Mode, req.Action, req.Keys).Return(nil, nil)
96		mockSaver.EXPECT().SetKeybinding(mock.Anything, req).Return(nil)
97
98		uc := usecase.NewSetKeybindingUseCase(mockProvider, mockSaver)
99
100		// Act
101		resp, err := uc.Execute(context.Background(), req)
102
103		// Assert
104		require.NoError(t, err)
105		assert.Empty(t, resp.Conflicts)
106		mock.AssertExpectationsForObjects(t, mockProvider, mockSaver)
107	})
108
109	t.Run("returns conflicts when detected", func(t *testing.T) {
110		// Arrange
111		mockProvider := mocks.NewMockKeybindingsProvider(t)
112		mockSaver := mocks.NewMockKeybindingsSaver(t)
113		req := port.SetKeybindingRequest{
114			Mode:   "pane",
115			Action: "split-right",
116			Keys:   []string{"r"},
117		}
118		conflicts := []port.KeybindingConflict{
119			{ConflictingAction: "other-action", ConflictingMode: "pane", Key: "r"},
120		}
121		mockProvider.EXPECT().CheckConflicts(mock.Anything, req.Mode, req.Action, req.Keys).Return(conflicts, nil)
122		mockSaver.EXPECT().SetKeybinding(mock.Anything, req).Return(nil)
123
124		uc := usecase.NewSetKeybindingUseCase(mockProvider, mockSaver)
125
126		// Act
127		resp, err := uc.Execute(context.Background(), req)
128
129		// Assert
130		require.NoError(t, err)
131		assert.Equal(t, conflicts, resp.Conflicts)
132		mock.AssertExpectationsForObjects(t, mockProvider, mockSaver)
133	})
134
135	t.Run("returns error when saver fails", func(t *testing.T) {
136		// Arrange
137		mockProvider := mocks.NewMockKeybindingsProvider(t)
138		mockSaver := mocks.NewMockKeybindingsSaver(t)
139		req := port.SetKeybindingRequest{
140			Mode:   "pane",
141			Action: "split-right",
142			Keys:   []string{"r"},
143		}
144		mockProvider.EXPECT().CheckConflicts(mock.Anything, req.Mode, req.Action, req.Keys).Return(nil, nil)
145		mockSaver.EXPECT().SetKeybinding(mock.Anything, req).Return(errors.New("save error"))
146
147		uc := usecase.NewSetKeybindingUseCase(mockProvider, mockSaver)
148
149		// Act
150		_, err := uc.Execute(context.Background(), req)
151
152		// Assert
153		require.Error(t, err)
154		assert.Contains(t, err.Error(), "save error")
155		mock.AssertExpectationsForObjects(t, mockProvider, mockSaver)
156	})
157
158	t.Run("returns error when saver is nil", func(t *testing.T) {
159		// Arrange
160		uc := usecase.NewSetKeybindingUseCase(nil, nil)
161		req := port.SetKeybindingRequest{
162			Mode:   "pane",
163			Action: "split-right",
164			Keys:   []string{"r"},
165		}
166
167		// Act
168		_, err := uc.Execute(context.Background(), req)
169
170		// Assert
171		require.Error(t, err)
172		assert.Contains(t, err.Error(), "saver is nil")
173	})
174
175	t.Run("returns error when mode is empty", func(t *testing.T) {
176		// Arrange
177		mockProvider := mocks.NewMockKeybindingsProvider(t)
178		mockSaver := mocks.NewMockKeybindingsSaver(t)
179		req := port.SetKeybindingRequest{
180			Mode:   "",
181			Action: "split-right",
182			Keys:   []string{"r"},
183		}
184
185		uc := usecase.NewSetKeybindingUseCase(mockProvider, mockSaver)
186
187		// Act
188		_, err := uc.Execute(context.Background(), req)
189
190		// Assert
191		require.Error(t, err)
192		assert.Contains(t, err.Error(), "mode is required")
193	})
194
195	t.Run("returns error when action is empty", func(t *testing.T) {
196		// Arrange
197		mockProvider := mocks.NewMockKeybindingsProvider(t)
198		mockSaver := mocks.NewMockKeybindingsSaver(t)
199		req := port.SetKeybindingRequest{
200			Mode:   "pane",
201			Action: "",
202			Keys:   []string{"r"},
203		}
204
205		uc := usecase.NewSetKeybindingUseCase(mockProvider, mockSaver)
206
207		// Act
208		_, err := uc.Execute(context.Background(), req)
209
210		// Assert
211		require.Error(t, err)
212		assert.Contains(t, err.Error(), "action is required")
213	})
214
215	t.Run("returns error for invalid mode", func(t *testing.T) {
216		// Arrange
217		mockProvider := mocks.NewMockKeybindingsProvider(t)
218		mockSaver := mocks.NewMockKeybindingsSaver(t)
219		req := port.SetKeybindingRequest{
220			Mode:   "invalid",
221			Action: "split-right",
222			Keys:   []string{"r"},
223		}
224
225		uc := usecase.NewSetKeybindingUseCase(mockProvider, mockSaver)
226
227		// Act
228		_, err := uc.Execute(context.Background(), req)
229
230		// Assert
231		require.Error(t, err)
232		assert.Contains(t, err.Error(), "invalid mode")
233	})
234}
235
236func TestResetKeybindingUseCase_Execute(t *testing.T) {
237	t.Run("successfully resets keybinding", func(t *testing.T) {
238		// Arrange
239		mockSaver := mocks.NewMockKeybindingsSaver(t)
240		req := port.ResetKeybindingRequest{
241			Mode:   "pane",
242			Action: "split-right",
243		}
244		mockSaver.EXPECT().ResetKeybinding(mock.Anything, req).Return(nil)
245
246		uc := usecase.NewResetKeybindingUseCase(mockSaver)
247
248		// Act
249		err := uc.Execute(context.Background(), req)
250
251		// Assert
252		require.NoError(t, err)
253		mock.AssertExpectationsForObjects(t, mockSaver)
254	})
255
256	t.Run("returns error when saver fails", func(t *testing.T) {
257		// Arrange
258		mockSaver := mocks.NewMockKeybindingsSaver(t)
259		req := port.ResetKeybindingRequest{
260			Mode:   "pane",
261			Action: "split-right",
262		}
263		mockSaver.EXPECT().ResetKeybinding(mock.Anything, req).Return(errors.New("reset error"))
264
265		uc := usecase.NewResetKeybindingUseCase(mockSaver)
266
267		// Act
268		err := uc.Execute(context.Background(), req)
269
270		// Assert
271		require.Error(t, err)
272		assert.Contains(t, err.Error(), "reset error")
273		mock.AssertExpectationsForObjects(t, mockSaver)
274	})
275
276	t.Run("returns error when saver is nil", func(t *testing.T) {
277		// Arrange
278		uc := usecase.NewResetKeybindingUseCase(nil)
279		req := port.ResetKeybindingRequest{
280			Mode:   "pane",
281			Action: "split-right",
282		}
283
284		// Act
285		err := uc.Execute(context.Background(), req)
286
287		// Assert
288		require.Error(t, err)
289		assert.Contains(t, err.Error(), "saver is nil")
290	})
291
292	t.Run("returns error when mode is empty", func(t *testing.T) {
293		// Arrange
294		mockSaver := mocks.NewMockKeybindingsSaver(t)
295		req := port.ResetKeybindingRequest{
296			Mode:   "",
297			Action: "split-right",
298		}
299
300		uc := usecase.NewResetKeybindingUseCase(mockSaver)
301
302		// Act
303		err := uc.Execute(context.Background(), req)
304
305		// Assert
306		require.Error(t, err)
307		assert.Contains(t, err.Error(), "mode is required")
308	})
309}
310
311func TestResetAllKeybindingsUseCase_Execute(t *testing.T) {
312	t.Run("successfully resets all keybindings", func(t *testing.T) {
313		// Arrange
314		mockSaver := mocks.NewMockKeybindingsSaver(t)
315		mockSaver.EXPECT().ResetAllKeybindings(mock.Anything).Return(nil)
316
317		uc := usecase.NewResetAllKeybindingsUseCase(mockSaver)
318
319		// Act
320		err := uc.Execute(context.Background())
321
322		// Assert
323		require.NoError(t, err)
324		mock.AssertExpectationsForObjects(t, mockSaver)
325	})
326
327	t.Run("returns error when saver fails", func(t *testing.T) {
328		// Arrange
329		mockSaver := mocks.NewMockKeybindingsSaver(t)
330		mockSaver.EXPECT().ResetAllKeybindings(mock.Anything).Return(errors.New("reset all error"))
331
332		uc := usecase.NewResetAllKeybindingsUseCase(mockSaver)
333
334		// Act
335		err := uc.Execute(context.Background())
336
337		// Assert
338		require.Error(t, err)
339		assert.Contains(t, err.Error(), "reset all error")
340		mock.AssertExpectationsForObjects(t, mockSaver)
341	})
342
343	t.Run("returns error when saver is nil", func(t *testing.T) {
344		// Arrange
345		uc := usecase.NewResetAllKeybindingsUseCase(nil)
346
347		// Act
348		err := uc.Execute(context.Background())
349
350		// Assert
351		require.Error(t, err)
352		assert.Contains(t, err.Error(), "saver is nil")
353	})
354}

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